4

下面一段简单的代码,用 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)在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

如果 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();
}
4

3 回答 3

13

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

C++ 中的语义protected意味着“可以从此类或任何派生类的方法访问此成员,但只有当被访问的对象的动态类型保证与“的类型相同或派生自 *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!
   }
};

这是设计使然-想法是Derived2可以对应如何处理其受保护的成员(什么是不变量等)有自己的看法,并且它应该严格位于它与其基类(及其派生类,但仅限于如果它决定不通过制作来隐藏该字段private)。跨层次访问与此模型相反,因为这实际上意味着基类提前决定整个层次结构;对于深层次结构之上的非常抽象的类,这可能是不可取的。

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

于 2009-11-24T04:10:41.227 回答
6

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

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

会编译。

我相信这是因为 11.5.1:

...如果访问 [编辑。to a protected member ] 是形成一个指向成员的指针,嵌套名称说明符应命名派生类(或从该类派生的任何类)。

于 2009-11-24T03:54:06.597 回答
2

由于对象是作为参数传递的,因此您不能直接访问私有/受保护的函数。

编辑:将 myclass 更改为 object

于 2009-11-24T03:50:02.503 回答