为什么 C++ 禁止私有继承 final class?
Why does C++ forbid private inheritance of a final class?
C++11 向 C++ 引入了 final
关键字。
它可以在虚拟方法或class上使用。
声明 class final 禁止 任何类型的继承:public,受保护和私有。
struct A final {
};
class B: private A {
};
error: base 'A' ^ is marked 'final'
虽然禁止 public 继承是合理的(例如,如果我的 class 没有虚拟析构函数,或出于其他原因),我为什么要禁止私有继承?
可能是如果 final
禁止 仅 public 继承 ,那么 std::string
和它在 std 中的其他朋友将是 final
-- 他们应该 -- 因为没有虚拟析构函数?
编辑:
Howard Hinnant 已经回答了 Why the standard containers are not final 但仍然有理由声明 class final 但允许私有继承。
继承就是继承。可访问性与它正交。它仅防止 静态地 将派生 class 视为基础,超出派生 class 的范围。在运行时间没有区别,如果允许私有继承,你可以这样写:
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
是为了完全防止进一步覆盖,那么私有继承必须包含在禁止中。
除了 Story Teller 所说的之外,考虑 引入 final
的原因:它应该有助于优化。
当一个class是final
,并且你有一个指向它的指针,编译器可以证明你正在调用哪个成员函数,即使是 virtual
。如果 class 不是 final
,该指针实际上可能是指向某个派生的 class 的指针,可以想象它可以覆盖 virtual
方法,强制执行完整的动态 vtable 查找。
不管是否继承private
,总是可以创建一个base-class指针。在 private
继承的情况下,创建这个 base-class 指针将限于派生 class、派生 class 以及派生 class 的任何基类=29=],这仍然比优化器可用于做出决定的代码多。因此,仅禁止 all 继承允许进行虚拟调用优化。
C++11 向 C++ 引入了 final
关键字。
它可以在虚拟方法或class上使用。
声明 class final 禁止 任何类型的继承:public,受保护和私有。
struct A final {
};
class B: private A {
};
error: base 'A' ^ is marked 'final'
虽然禁止 public 继承是合理的(例如,如果我的 class 没有虚拟析构函数,或出于其他原因),我为什么要禁止私有继承?
可能是如果 final
禁止 仅 public 继承 ,那么 std::string
和它在 std 中的其他朋友将是 final
-- 他们应该 -- 因为没有虚拟析构函数?
编辑:
Howard Hinnant 已经回答了 Why the standard containers are not final 但仍然有理由声明 class final 但允许私有继承。
继承就是继承。可访问性与它正交。它仅防止 静态地 将派生 class 视为基础,超出派生 class 的范围。在运行时间没有区别,如果允许私有继承,你可以这样写:
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
是为了完全防止进一步覆盖,那么私有继承必须包含在禁止中。
除了 Story Teller 所说的之外,考虑 引入 final
的原因:它应该有助于优化。
当一个class是final
,并且你有一个指向它的指针,编译器可以证明你正在调用哪个成员函数,即使是 virtual
。如果 class 不是 final
,该指针实际上可能是指向某个派生的 class 的指针,可以想象它可以覆盖 virtual
方法,强制执行完整的动态 vtable 查找。
不管是否继承private
,总是可以创建一个base-class指针。在 private
继承的情况下,创建这个 base-class 指针将限于派生 class、派生 class 以及派生 class 的任何基类=29=],这仍然比优化器可用于做出决定的代码多。因此,仅禁止 all 继承允许进行虚拟调用优化。