为啥受保护的继承会导致 dynamic_cast 失败?

Posted

技术标签:

【中文标题】为啥受保护的继承会导致 dynamic_cast 失败?【英文标题】:Why does protected inheritance cause dynamic_cast to fail?为什么受保护的继承会导致 dynamic_cast 失败? 【发布时间】:2012-09-27 17:26:35 【问题描述】:

我将 C++ 基类更改为 protected 继承,而我的 dynamic_cast(s) 停止工作。

为什么要将继承更改为protected 会更改dynamic_cast 的行为?

struct Base 
  static Base *lookupDerived(); // Actually returns a Derived * object.
;

struct Derived : protected /* Switch this to public to get it working */ Base 
 static void test() 
   Base *base = lookupDerived();

   if (dynamic_cast<Derived *>(base)) 
      std::cout << "It worked (we must be using public inheritance)." << std::endl;
    else 
      std::cout << "It failed (we must be using protected inheritance)." << std::endl;
   
;

【问题讨论】:

【参考方案1】:

作为外部用户,您无法访问类的受保护或私有成员。这同样适用于受保护或私有继承。类的作者不希望外部用户访问受保护/私有父类,就像他们希望外部用户访问受保护/私有成员一样。

一个原因:假设父类有一个非虚析构函数。从基类指针删除实例派生类将导致未定义的行为。使父类受保护/私有意味着你不能这样做(见脚注)。

另一个原因:假设相关类的作者不希望外部用户访问父类的公共成员。可以使用公共继承 (is-a) 并将这些公共接口降级为受保护或私有,但这将违反 Liskov 替换原则。受保护或私有继承不是 is-a 关系。这些公共方法通过受保护或私有继承变为受保护或私有。 Liskov 替换没有问题,因为受保护/私有继承不是 is-a

脚注:有一个丑陋的方法来解决这个问题:使用 C 风格的强制转换。外部用户可以投射 派生类指针指向基类指针,即使基类不可访问。对我来说,这是使用-Wold-style-cast -Werror 编译的另一个原因。

【讨论】:

【参考方案2】:

当您将继承更改为受保护时,您的两个类之间的关系从对象外部隐藏。

【讨论】:

【参考方案3】:

私有(或受保护)继承在语义上与公共继承不同。 这不是“is-a”关系,而是“implemented in terms”关系。

意味着您不能将基类用作派生对象的句柄。

【讨论】:

以上是关于为啥受保护的继承会导致 dynamic_cast 失败?的主要内容,如果未能解决你的问题,请参考以下文章

为啥不能将继承的受保护构造函数公开?

C++ 为啥要使用公有、私有或受保护的继承?

为啥Java中允许受保护的静态? [关闭]

为啥我们不能在 kotlin 中将类的可见性标记为“受保护”?

为啥受保护的构造函数会在此代码中引发错误?

为啥我不能访问派生构造函数的成员初始化列表中继承的受保护字段?