又发生了什么
看如下代码
class VisibilityTest
{
public:
virtual void doIt() { std::cout << "Base\n"; }
};
class DVisibilityTest : private VisibilityTest
{
private:
virtual void doIt() override { std::cout << "Derived\n"; }
};
GCC报错信息: 'VisibilityTest' is an inaccessible base of 'DVisibilityTest'
解释
通常我们认为'private'继承仅会改变基类成员对外部的可见性
, 但是这个例子明显感觉有违常识
其实private
继承的真实含义除了改变成员可见性外, 还有一个是就是继承信息的可见性. 如下
class A {};
class B : private A {}; // 这里同时意味着B继承自A的这条信息只有B知道, 其他人都不知道.
同理, protect和public继承也包含的继承信息的可见性
原来是要干什么
从代码可以看出, 原来是要测试可见性的重定义问题. 在C++中, 基类中的方法在子类中可以重写其可见性. 如下
class VisibilityTest
{
public:
virtual void doIt() { std::cout << "Base\n"; }
};
class DVisibilityTest : public VisibilityTest
{
private:
virtual void doIt() override { std::cout << "Derived\n"; }
};
int main(int argc, char* argv[])
{
VisibilityTest* pVT = new DVisibilityTest();
pVT->doIt();
// 下面的就无法运行, 编译报错doIt是private.
/*
DVisibilityTest* pDVT = new DVisibilityTest();
pDVT->doIt();
*/
return 0;
}
将可见性修饰符反过来, 逻辑也就翻过来了, 通过基类指针多态调用就会报错, 通过子类指针编译运行通过.
但是这就引入一个思考, 我们应该这样做吗?
可见性覆写既然编译器和C++标准没有禁止, 说明这个特性完全没有问题, 有些特殊情况可以使用. 但是通常的
逻辑下, 个人认为还是不要这么做:
因为继承的通常逻辑是, 子类可以替代基类, 即基类能做的, 子类都可以做, 甚至做基类做不到的, 但是如果子类
将可见性覆写为private, 这个逻辑和我们通常的认识有冲突(只有基类能做, 子类做不了). 因此通常不做么做比较好.
当然这个可见性覆写因该还有挖掘的地方, 后续在补充吧.