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

时间:2009-11-24 03:45:52

标签: 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);
}

(/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();
}

3 个答案:

答案 0 :(得分: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隐藏该字段时)。跨层次访问与此模型相反,因为它实际上意味着基类预先决定整个层次结构;对于深度层次结构之上非常抽象的类,这可能是不可取的。

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

答案 1 :(得分:6)

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

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

会编译。

我认为这是因为11.5.1:

  

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

答案 2 :(得分:2)

由于对象作为参数传递,因此无法直接访问私有/受保护函数。

编辑: 将myclass更改为object