友好和访问级别的继承

时间:2016-12-10 12:05:30

标签: c++

我有以下测验问题:

#include <iostream>
using namespace std;

struct A
{
    void ohai() { cout  << "ohai" << endl; }
};

struct C : private A {
    friend int main();
};

struct X : C {};
struct Y : private C {};

int main() {    
    C().ohai()  // OK
    X().ohai(); // OK
    Y().ohai(); // Not OK
}

事情是C类私下从A继承。因此,A的所有成员,甚至公众,现在都变成了C的私人。 C类也用main函数声明友好(这是好的,现在&#39; main&#39;函数可以调用C的私有方法)。 然后有类X和Y,都来自C。 X公开来自C,Y来自C私下。

在&#39; main&#39; function我创建C类实例并调用&#39; ohai&#39;从A私下继承的方法,这很好用,因为main是C的朋友。 然后我创建了X类的实例,然后调用&#39; ohai&#39; - 这令人惊讶的工作! 但是当我创建Y类的实例时,这不起作用!

我知道继承不是不可靠的。所以这不是继承友善,这使得主要的&#39;打电话给'ohai&#39;对类X的对象的方法。 类Y的东西证实了,因为它足以将继承类型更改为private来阻止这种工作。

我想知道为什么打电话给'ohai&#39;在X对象上。继承不能提升函数的级别(从私有到公共),所以如果X继承自C,甚至公开,C中的所有私有方法都应该在X中保持私有。并且由于友好性不可继承,所以&#39; main&# 39;方法不应该能够调用X的私有方法。 Y类私有地从C继承,这使得C的所有成员在X中都是私有的,但是&#39; ohai&#39;方法在C中已经是私有的(因为C从A私下继承)所以这不应该改变anythig,但不知何故它确实如此(与X相比)。

请帮我理解这个问题。 最好的祝福 YotKay

1 个答案:

答案 0 :(得分:1)

我不完全确定我的回答。如果我错了,请纠正我。

我相信这里发生的事情是,当您致电X().ohai()时,this中的X指针会隐式投放到其基类C,这会授予友谊main。更准确地说,当编译器在ohai中查找X时,它在X中找不到它,也不在其直接基类C中找到它,而是在{{{}}中找到它1}}。友谊和其他访问控制机制不会干扰编译器应该找到成员函数的位置。它的效果是在找到成员之后发生的。一旦编译器在A中找到ohai,就需要将A指针(X *)强制转换为this。 (到目前为止,我很确定我是对的)。 A *是公共继承自X的,因此可以将其转换为C。并C *给予C友谊,因此可以继续将其投放到main。因此它可以调用A *。 (最后一部分不是很精确,但更容易理解)。

例如,尝试以下方法,

ohai

第一次演员没有问题,而第二次演员会在Clang中给你以下错误,

int main()
{
    X x;
    Y y;
    static_cast<A *>(&x);
    static_cast<A *>(&y);
}

如果删除test.cpp:24:22: error: cannot cast 'Y' to its private base class 'A' static_cast<A *>(&y); ^ test.cpp:15:11: note: constrained by private inheritance here class Y : private C ^~~~~~~~~ 声明,第一次播放也会失败,但原因不同。

&#34;友谊不能继承&#34;是正确的,但它实际上与此处发生的事情没有任何关系

如果删除好友声明,请尝试以下操作

friend

第一次演员会因访问控制而失败,而第二次演员会成功。

对main的友谊不仅授予其访问int main() { X x; Y y; static_cast<A *>(&x); static_cast<C *>(&x); } 私有成员的权限,还授予其私有基类。对于这个问题,请在有和没有朋友声明的情况下尝试以下内容

C

最后,请尝试以下

int main()
{
    C c;
    static_cast<A *>(&c);
}

函数struct A { void ohai() { std::cout << "ohai" << std::endl; } }; struct C : private A { using A::ohai; }; struct X : C { void foo() { C::ohai(); } // static_cast<C *>(this)->ohai(); void bar() { A::ohai(); } // static_cast<A *>(this)->ohai(); }; int main() { X x; x.foo(); x.bar(); x.ohai(); } 可以,但foo会失败。因为bar可以投放到其直接基地X,并在C中将ohai公开。但无法将其设为C,并在A中调用ohai