我有以下测验问题:
#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
答案 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