虚析构函数必须显式声明,否则父类指针删除子类对象时只调用父类析构,导致子类资源未释放而崩溃或泄漏;public继承保持访问级别,对应“is-a”关系,private/protected继承改变成员对外可见性,实际应优先用组合而非private继承。

继承不是“抄代码”,而是让子类自动获得父类的成员和接口能力;没写对 public、protected 或漏掉虚析构函数,运行时就可能崩溃或内存泄漏。
为什么子类对象一析构就崩?——虚析构函数必须显式加
父类指针指向子类对象是常见操作,比如用 std::vector<:unique_ptr>></:unique_ptr> 存多种派生类型。但若 Base 的析构函数不是 virtual,delete 时只会调用 Base::~Base(),子类自己的清理逻辑(比如释放 new 出来的资源)完全不会执行。
实操建议:
- 只要类设计为被继承(哪怕当前没子类),析构函数必须声明为
virtual,哪怕它是空的:virtual ~Base() = default;
- 不推荐写
virtual ~Base() {},因为编译器无法自动标记为noexcept,而默认构造/析构在移动语义中常需noexcept保证异常安全 - 如果类明确禁止继承,加
final关键字更直接:class Leaf final : public Base { ... };
public / protected / private 继承的区别到底在哪?
不是“能不能访问”,而是“外部代码通过子类能否访问父类成员”。private 继承后,父类所有成员(包括 public 成员)在子类内部变成 private;protected 继承则全部变成 protected;只有 public 继承才保持原有访问级别对外可见。
立即学习“C++免费学习笔记(深入)”;
实操建议:
- 99% 的业务场景只用
public继承,它对应“is-a”关系(比如Dogis-aAnimal) -
private继承本质是“has-a”的替代写法,但可读性差,优先用组合:class Dog { Animal impl_; };而不是class Dog : private Animal { }; -
protected继承极少用,通常只出现在框架底层封装中,普通项目几乎可以忽略
子类怎么调用父类构造函数?初始化列表里写清楚
子类没有默认继承父类构造函数(C++11 后可用 using Base::Base; 继承,但有严格限制)。如果不显式调用,编译器会尝试调用父类默认构造函数;若父类没默认构造函数,直接报错:
error: no matching function for call to 'Base::Base()'
实操建议:
- 在子类构造函数初始化列表中,第一项必须是父类构造调用:
Derived(int x) : Base(x), member_(x * 2) {} - 不能在构造函数体内用
Base(x)补救——那只是临时创建一个匿名Base对象,跟当前对象无关 - 若父类构造函数是
explicit,子类调用也必须显式,否则隐式转换会被拒绝
继承链越深,对象布局越难预测;多重继承时虚基类的偏移计算、vtable 布局、RTTI 开销都会真实影响性能和调试难度。别为了“复用”硬套继承,先问一句:这个关系真的能用“is-a”说清吗?










