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

Ara*_*raK 4 c++ standards standards-compliance

下面简单的一段代码,用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);
}
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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


@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();
}
Run Code Online (Sandbox Code Playgroud)

Pav*_*aev 13

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

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

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

 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!
   }
};
Run Code Online (Sandbox Code Playgroud)

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

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


Tod*_*ner 6

我相信g ++和comeau是正确的.受保护成员的说明符必须是"access"或派生类型,所以我相信代码:

void (myclass::*function) () = &access::print;
Run Code Online (Sandbox Code Playgroud)

会编译.

我相信这是因为11.5.1:

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