非公共 C++ 继承在实践中使用的频率如何? [重复]

问题描述 投票:0回答:6

可能重复:
什么时候应该使用 C++ 私有继承?

我想创建这个社区维基,但没有看到按钮...有人可以添加它吗?

我想不出任何以非公开方式从类派生的案例,并且我不记得当时看到过执行此操作的代码。

我想听听现实世界中有用的示例和模式。

c++ inheritance
6个回答
7
投票

您的里程可能会有所不同...

最核心的答案是非公有继承是没有用的。

就我个人而言,我在两种情况下使用它:

  • 如果可能的话,我想触发空基优化1(通常,在模板代码中,谓词作为参数传递)
  • 我想重写类中的
    virtual
    函数

无论哪种情况,我都会使用

private
继承,因为继承本身就是一个实现细节。

我看到人们在编写包装器或扩展行为时更自由地、近乎系统地使用

private
继承,而不是组合。 C++ 不提供“简单”的委托语法,因此这样做允许您编写
using Base::method;
来立即提供方法,而不是编写正确的转发调用(及其所有重载)。我认为这是不好的形式,尽管它确实节省了时间。

1 通过添加

[[no_unique_address]]
属性,空基优化在 C++20 中已过时。


3
投票

如果您选择继承来开发包装器,那么私有继承是正确的选择。您不再需要或不想从包装类外部访问基类的方法和成员。

class B;
class A
{
public:
   A();
   void foo(B b);
};

class BWrap;
class AWrap : private A
{
public:
   AWrap();
   void foo(BWrap b);
};

//no longer want A::foo to be accessible by mistake here, so make it private

3
投票

由于

private
继承的唯一已知用途是实现继承,并且由于这始终可以使用包含来完成(使用起来不太简单,但更好地封装了关系),我想说它使用得太频繁了。

(因为没有人告诉我

protected
继承意味着什么,所以我们假设没有人知道它是什么,并假装它不存在。)


2
投票

有时继承既没有任何

virtual
函数也没有
virtual
析构函数的类(例如 STL 容器),您可能必须采用非
public
继承。例如

template<typename T>
struct MyVector : private std::vector<T>
{ ... };

这将不允许基类 (

vector<>
) 的句柄(指针或引用)获取派生
class
(
MyVector<>
):

vector<int> *p = new MyVector<int>; // compiler error
...
delete p;  // undefined behavior: ~vector() is not 'virtual'!

由于我们在第一行本身就遇到编译器错误,因此我们将避免后续行中的未定义行为


2
投票

如果您从没有虚拟析构函数的类派生,那么公共继承会导致该类的用户可以在指向基类的指针上调用delete,从而导致未定义的行为。
在这种情况下,使用私有继承是有意义的。

最常见的示例是从没有虚拟析构函数的 STL 容器私有派生。


C++FAQ 有一个很好的私有继承示例,可以扩展到许多实际场景。

私有继承的合法、长期使用是当您想要构建一个使用 Wilma 类中的代码的 Fred 类,并且 Wilma 类中的代码需要调用新类 Fred 中的成员函数时。在这种情况下,Fred 调用 Wilma 中的非虚拟对象,而 Wilma 调用自身(通常是纯虚拟对象),这些都被 Fred 覆盖。如果用组合来做到这一点会困难得多。

代码示例:

class Wilma {
 protected:
   void fredCallsWilma()
     {
       std::cout << "Wilma::fredCallsWilma()\n";
       wilmaCallsFred();
     }
   virtual void wilmaCallsFred() = 0;   // A pure virtual function
 };

 class Fred : private Wilma {
 public:
   void barney()
     {
       std::cout << "Fred::barney()\n";
       Wilma::fredCallsWilma();
     }
 protected:
   virtual void wilmaCallsFred()
     {
       std::cout << "Fred::wilmaCallsFred()\n";
     }
 }; 

1
投票

继承时使用非公有(几乎总是私有)继承 (仅)行为,而不是界面。 我大部分时间都用过,但没用过 独家,在 mixin 中。

为了更好地讨论该主题,您可能需要阅读 Barton 和 Nackman(科学与工程 C++:高级简介 技术和示例,ISBN 0-201-53393-6。 尽管有这个名字,但这本书的大部分内容都是 适用于所有 C++,而不仅仅是科学和工程 应用程序。 尽管它已经过时了,但仍然值得一读。)

© www.soinside.com 2019 - 2024. All rights reserved.