Bro*_*her 31 c++ inheritance private-inheritance
我始终认为私有继承仅仅意味着类型不会告诉外部它是从某个基类继承的。不过,似乎还有更多的限制。
考虑以下最小示例:
struct MyInterface {};
struct MyImpl : private MyInterface {};
struct Inherited : public MyImpl {
// Error: 'MyInterface' not accessible because 'MyImpl' uses 'private' to inherit from 'MyInterface'
void doSomething(MyInterface* mi) {}
};
struct Noninherited {
// All fine!
void doSomething(MyInterface* mi) {}
};
Run Code Online (Sandbox Code Playgroud)
Clang、GCC 和 MSVC 都拒绝此代码。鉴于我之前的假设,我本以为一切都会好起来的。
doSomething只是需要一个指向 的指针MyInterface,但它不会告诉外界其继承层次结构中Inherited有哪些MyInterface内容。在我看来,私有继承不仅不告诉外界继承结构,反而使整个继承结构完全“忘记”继承类型的存在。
这是理解私有继承的正确“思维模型”吗?还有其他意想不到的限制吗?
Yks*_*nen 40
发生这种情况是由于注入类名、不合格的名称查找规则以及名称查找在检查可访问性之前完成的事实。
注入类名是一种使类名在该类定义中可用的机制。
现在,类定义中的非限定名称查找规则规定,首先搜索类的范围,然后递归搜索任何基类的范围,只有在此之后(以及更多步骤),您才能在命名空间范围中执行正常搜索。
把这一切放在一起:
MyInterface范围内有 2 个名称Inherited- 一个作为注入类名称,另一个位于与Inherited(全局名称空间)相同的名称空间中。Inherited查找MyInterface为继承自 的注入类名称MyImpl。名称查找已满足,不再搜索该名称的其他实例。MyInterface但是,继承自的名称MyImpl无法访问Inherited,因为存在private继承 - 会发生错误。解决这个问题的方法是将非限定名称查找更改为限定名称查找:
struct Inherited : public MyImpl {
void doSomething(::MyInterface* mi) {}
};
Run Code Online (Sandbox Code Playgroud)
现在,注入的类名无法满足名称查找,因为您明确地MyInterface从全局名称空间中请求,而不是任何MyInterface恰好匹配的名称空间。由于全局命名空间中的名称MyInterface是公共的(就像所有命名空间名称一样),因此可以毫无问题地使用它。