代码之家  ›  专栏  ›  技术社区  ›  Khaled Alshaya

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

  •  4
  • Khaled Alshaya  · 技术社区  · 16 年前

    下面这段简单的代码是用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++是正确的,如何访问类的受保护成员?还有别的办法吗?


    @你是说我不应该传递一个类型的对象吗 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 回复  |  直到 16 年前
        1
  •  6
  •   Todd Gardner    16 年前

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

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

    会编译。

    我认为这是因为11.5.1:

    …如果访问 member]是指向 成员,嵌套名称说明符 应命名派生类(或 从该类派生的类)。

        2
  •  13
  •   Pavel Minaev    16 年前

    这是正确的。上面引用了标准的相关部分,但这里给出了其价值的理由。

    的语义 protected 在C++中,“这个成员可以从这个类或任何派生类的方法中访问,但是 只有当被访问对象的动态类型被保证与 *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 )跨层次访问与此模型相反,因为它实际上意味着基类提前决定整个层次结构;对于深层层次结构之上的非常抽象的类,这可能是不可取的。

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

        3
  •  2
  •   Suroot    16 年前

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

    编辑: 已将MyClass更改为对象