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

发布于 2024-08-11 20:16:28 字数 1276 浏览 4 评论 0原文

下面这段简单的代码,用 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();
}

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

#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.

g++ 4.4.1 gives me an error:

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?


@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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

平安喜乐 2024-08-18 20:16:28

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

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

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

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".

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.

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.

ら栖息 2024-08-18 20:16:28

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

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

会编译。

我相信这是因为 11.5.1:

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

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:

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

would compile.

I believe this is because of 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).

澜川若宁 2024-08-18 20:16:28

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

编辑:
将 myclass 更改为对象

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

Edit:
Changed myclass to object

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文