这是标准的C ++代码吗?

时间:2022-09-01 19:12:01

The following simple piece of code, compiles with VC2008 but g++ rejects the code:

下面简单的一段代码,用VC2008编译但g ++拒绝代码:

#include <iostream>

class myclass
{
protected:
    void print() { std::cout << "myclass::print();"; }
};

struct access : private myclass
{
    static void access_print(myclass& object)
    {
        // g++ and Comeau reject this line but not VC++
        void (myclass::*function) () = &myclass::print;

        (object.*function)();
    }
};

int main()
{
    myclass object;
    access::access_print(object);
}

(/W4) is turned on in VC, but it doesn't give any warning.

(/ W4)在VC中打开,但它没有发出任何警告。

g++ 4.4.1 gives me an error:

g ++ 4.4.1给出了一个错误:

correct.cpp: In static member function ‘static void access::access_print(myclass&)’:
correct.cpp:6: error: ‘void myclass::print()’ is protected

If g++ is correct, how do I access a protected member of a class? is there another way?

如果g ++是正确的,我如何访问类的受保护成员?有另一种方式吗?


@Suroot Do you mean that I shouldn't pass an object of type myclass? It doesn't matter actually, g++ gives the same error but VC compiles the code without any warning.

@Suroot你是说我不应该传递myclass类型的对象?实际上并不重要,g ++给出了相同的错误,但VC编译代码时没有任何警告。

#include <iostream>

class myclass
{
protected:
    void print() { std::cout << "myclass::print();"; }
};

struct access : private myclass
{
    static void access_print()
    {
        myclass object;
        void (myclass::*function) () = &myclass::print;

        (object.*function)();
    }
};

int main()
{
    access::access_print();
}

3 个解决方案

#1


6  

I believe g++ and comeau are correct. The specifier for a protected member must be of type "access" or derived, so I believe the code:

我相信g ++和comeau是正确的。受保护成员的说明符必须是“access”或派生类型,因此我相信代码:

void (myclass::*function) () = &access::print;

would compile.

I believe this is because of 11.5.1:

我相信这是因为11.5.1:

... If the access [ed. to a protected member ] is to form a pointer to member, the nested-name-specifier shall name the derived class (or any class derived from that class).

...如果访问[ed。对于受保护的成员]是形成指向成员的指针,嵌套名称说明符应命名派生类(或从该类派生的任何类)。

#2


13  

This is correct. The relevant part of the Standard has been quoted above, but here's the rationale for what it's worth.

这是对的。上面引用了标准的相关部分,但这是它的价值的基本原理。

The semantics of protected in C++ means "this member can be accessed from methods of this class or any derived classes, but only when dynamic type of object being accessed is guaranteed to be the same as, or derived from, the type of *this".

C ++中protected的语义意味着“这个成员可以从这个类的方法或任何派生类访问,但只有当被访问的对象的动态类型保证与* this的类型相同或派生时” 。

The latter bit may not quite be obvious, so here is an example:

后一点可能不太明显,所以这是一个例子:

 class Base {
 protected:
     int X;
 };

class Derived : public Base {
   void Foo(Base* b, Derived* d) {
       this->X = 123; // okay - `this` is definitely either Derived
                      // or inherited from Derived

       d->X = 456;    // also okay, for the same reason

       b->X = 789;    // NOT OKAY; b could point to instance of some other class
                      // Derived2, which isn't inherited from Derived!
   }
};

This is by design - the idea is that Derived2 could have its own opinion on how its protected members should be handled (what are the invariants, etc), and it should be strictly between it and its base class (and its derived classes, but only if it decides to not hide that field by making it private). Cross-hierarchy access is contrary to this model, since it would effectively mean that the base class decides for the entire hierarchy in advance; for very abstract classes on top of deep hierarchies, this can be undesirable.

这是设计 - 想法是Derived2可以对如何处理受保护的成员(不变量等等)有自己的看法,它应该严格地介于它和它的基类(及其派生类之间,但是只有当它决定不通过私有而隐藏该字段时)。跨层次访问与此模型相反,因为它实际上意味着基类预先决定整个层次结构;对于深度层次结构之上的非常抽象的类,这可能是不可取的。

Now back to your specific problem - it should be fairly obvious by now. Once you obtain a member function pointer, you may call the function pointed to by that pointer with any receiver of a matching type. For a protected method of a base class, this means that, if you could obtain a pointer to it typed to the base class (rather than your own class), you could then call it, passing it a pointer to a type different from your class (or derived from it), violating the rules for protected access outlined above. Therefore, you are not permitted to do this.

现在回到你的具体问题 - 现在应该是相当明显的。获得成员函数指针后,可以使用匹配类型的任何接收器调用该指针指向的函数。对于基类的受保护方法,这意味着,如果你可以获得一个指向它的指针到基类(而不是你自己的类),你可以调用它,向它传递一个指向不同于你的类型的指针类(或从中派生),违反了上面概述的受保护访问规则。因此,您不允许这样做。

#3


2  

Since object is being passed as a parameter, you cannot access private/protected functions directly.

由于object是作为参数传递的,因此您无法直接访问private / protected函数。

Edit: Changed myclass to object

编辑:将myclass更改为object

#1


6  

I believe g++ and comeau are correct. The specifier for a protected member must be of type "access" or derived, so I believe the code:

我相信g ++和comeau是正确的。受保护成员的说明符必须是“access”或派生类型,因此我相信代码:

void (myclass::*function) () = &access::print;

would compile.

I believe this is because of 11.5.1:

我相信这是因为11.5.1:

... If the access [ed. to a protected member ] is to form a pointer to member, the nested-name-specifier shall name the derived class (or any class derived from that class).

...如果访问[ed。对于受保护的成员]是形成指向成员的指针,嵌套名称说明符应命名派生类(或从该类派生的任何类)。

#2


13  

This is correct. The relevant part of the Standard has been quoted above, but here's the rationale for what it's worth.

这是对的。上面引用了标准的相关部分,但这是它的价值的基本原理。

The semantics of protected in C++ means "this member can be accessed from methods of this class or any derived classes, but only when dynamic type of object being accessed is guaranteed to be the same as, or derived from, the type of *this".

C ++中protected的语义意味着“这个成员可以从这个类的方法或任何派生类访问,但只有当被访问的对象的动态类型保证与* this的类型相同或派生时” 。

The latter bit may not quite be obvious, so here is an example:

后一点可能不太明显,所以这是一个例子:

 class Base {
 protected:
     int X;
 };

class Derived : public Base {
   void Foo(Base* b, Derived* d) {
       this->X = 123; // okay - `this` is definitely either Derived
                      // or inherited from Derived

       d->X = 456;    // also okay, for the same reason

       b->X = 789;    // NOT OKAY; b could point to instance of some other class
                      // Derived2, which isn't inherited from Derived!
   }
};

This is by design - the idea is that Derived2 could have its own opinion on how its protected members should be handled (what are the invariants, etc), and it should be strictly between it and its base class (and its derived classes, but only if it decides to not hide that field by making it private). Cross-hierarchy access is contrary to this model, since it would effectively mean that the base class decides for the entire hierarchy in advance; for very abstract classes on top of deep hierarchies, this can be undesirable.

这是设计 - 想法是Derived2可以对如何处理受保护的成员(不变量等等)有自己的看法,它应该严格地介于它和它的基类(及其派生类之间,但是只有当它决定不通过私有而隐藏该字段时)。跨层次访问与此模型相反,因为它实际上意味着基类预先决定整个层次结构;对于深度层次结构之上的非常抽象的类,这可能是不可取的。

Now back to your specific problem - it should be fairly obvious by now. Once you obtain a member function pointer, you may call the function pointed to by that pointer with any receiver of a matching type. For a protected method of a base class, this means that, if you could obtain a pointer to it typed to the base class (rather than your own class), you could then call it, passing it a pointer to a type different from your class (or derived from it), violating the rules for protected access outlined above. Therefore, you are not permitted to do this.

现在回到你的具体问题 - 现在应该是相当明显的。获得成员函数指针后,可以使用匹配类型的任何接收器调用该指针指向的函数。对于基类的受保护方法,这意味着,如果你可以获得一个指向它的指针到基类(而不是你自己的类),你可以调用它,向它传递一个指向不同于你的类型的指针类(或从中派生),违反了上面概述的受保护访问规则。因此,您不允许这样做。

#3


2  

Since object is being passed as a parameter, you cannot access private/protected functions directly.

由于object是作为参数传递的,因此您无法直接访问private / protected函数。

Edit: Changed myclass to object

编辑:将myclass更改为object