【问题标题】:Why does C++ forbid private inheritance of a final class?为什么 C++ 禁止对 final 类进行私有继承?
【发布时间】:2019-05-24 00:48:37
【问题描述】:

C++11 为 C++ 引入了final 关键字。

它可以用于虚方法

声明一个最终类禁止任何类型的继承:公共的、受保护的和私有的。

struct A final {
};

class B: private A {
};

 error: base 'A' ^ is marked 'final'

虽然禁止公共继承是合理的(例如,如果我的类没有虚拟析构函数,或出于其他原因),我为什么要禁止私有继承?

如果final 禁止只有公共继承,那么std::string 和它在std 中的其他朋友可能会是final -- 他们应该这样做 -- 因为没有虚拟析构函数?

编辑:

Howard Hinnant 已经回答了Why the standard containers are not final,但仍然有理由声明一个最终类但允许私有继承。

【问题讨论】:

  • 没有虚拟析构函数无论如何都不会禁止或限制继承。它仅通过指向基类的指针使对对象的所有权出错。所以这不是制作std::string 和大多数其他库类final 的原因。
  • 这个假设的功能将如何工作?假设您可以从最终类派生(如果只是私下)。虚函数会被视为最终函数吗?

标签: c++ final


【解决方案1】:

继承就是继承。可访问性与它正交。它只防止静态地将派生类视为基类,超出派生类的范围。在运行时没有区别,如果允许私有继承,你可以这样写:

struct C {
    virtual void foo() {}
};

struct A final : C {
    virtual void foo() {}
};

void baz(A& ref) { ref.foo(); }

class B: private A {
   virtual void foo() {}
   void bar() {
       baz(*this);
   }
};

私有继承不会阻止您使用运行时多态性。如果final 旨在完全防止进一步覆盖,则必须在禁止中包含私有继承。

【讨论】:

  • 漂亮的例子,这让我想起了一个奇特的规则:如果 B 是从 A 私有继承的,那么 B 类型的对象仍然被认为是 B 本身内部的“A”!恕我直言,如果规范在这种情况下(私有继承)不允许 B 覆盖 A 的私有虚拟,即使没有 final 也会更好!但这对于我猜的一个非常罕见的情况来说将是一个额外的规则......而且可能根本不是一个好的规则。更好的规则可能是:小心私有继承。
  • @AmirKirsh - 主规则的一个小节。一般要小心 C++ :)
  • 私自继承自主规则? :-)
  • 有可能让final 只限制多态层次结构。在那种情况下,可访问性也不会出现。
  • @Deduplicator - 可能有。但是提出它的论文想给班级作者一个工具,说“你不能继承这个,时期”。这也不是没有道理,这也是委员会的方向。
【解决方案2】:

除了 Story Teller 所说的之外,请考虑引入final原因:它应该有助于优化。

当一个类是final,并且你有一个指向它的指针时,编译器可以证明你正在调用哪个成员函数,即使它是virtual。如果该类不是final,则该指针实际上可能是指向某个派生类的指针,这可能会覆盖virtual 方法,从而强制进行完整的动态vtable 查找。

无论继承是否为private,总是可以创建一个基类指针。在private 继承的情况下,这个基类指针的创建将被限制在派生类、派生类和派生类的任何基类中,这仍然比优化器可用于使其生成的代码更多。决定。因此,只有禁止 all 继承才允许进行虚拟调用优化。

【讨论】:

    猜你喜欢
    • 2015-10-07
    • 2016-05-29
    • 2022-01-04
    • 2013-04-23
    • 2019-12-05
    • 2014-09-09
    • 1970-01-01
    • 2011-12-21
    • 2016-12-12
    相关资源
    最近更新 更多