virtual函数起作用需基类声明virtual、派生类同签名重写(const/引用需一致),推荐用override标记;虚基类解决菱形继承的二义性与冗余,由最派生类调用其构造函数。

virtual函数怎么写才真正起作用
只有在基类中用 virtual 声明的成员函数,派生类里用相同签名(函数名、参数类型、const 限定)重写时,才能实现运行时多态。光在派生类加 virtual 没用,基类没标就只是普通重载。
常见错误:漏掉 const 或引用修饰符,导致函数签名不一致,编译器认为是新函数而非重写 —— 这时调用仍走基类版本,virtual 形同虚设。
- 必须在基类声明处加
virtual,派生类可加可不加(C++11 起推荐加override显式标记) - 返回类型需协变(如基类返回
Base*,派生类可返回Derived*),否则编译报错 - 构造函数不能是
virtual;析构函数建议声明为virtual,尤其当对象可能通过基类指针删除时
虚基类解决的是什么问题
多重继承中,若两个父类都继承自同一个祖父类,子类默认会包含两份该祖父类的子对象 —— 导致二义性(比如调用祖父类函数时编译器不知道选哪份)和内存冗余。虚基类强制让这个公共祖先只被继承一次。
典型场景:class A 是根,class B : virtual public A 和 class C : virtual public A,再有 class D : public B, public C —— 此时 D 中只有一个 A 子对象。
立即学习“C++免费学习笔记(深入)”;
- 关键字
virtual必须出现在**最直接继承路径**上(即B和C的继承列表里),在D里补没用 - 虚基类的构造函数由**最派生类**(这里是
D)负责调用,B和C的构造函数里对A的初始化会被忽略 - 虚基类带来轻微性能开销:访问其成员需通过额外偏移量查表,且对象布局更复杂
virtual关键字在继承声明中的位置和含义
virtual 出现在继承冒号后、访问说明符前,例如 class B : virtual public A。它修饰的是“继承关系本身”,不是类或函数。
注意它和 virtual 成员函数完全无关,只是共用一个关键字。混淆这点容易误以为“虚继承会让所有函数自动变虚函数”——不会。
- 写成
class B : public virtual A语法错误,顺序不可颠倒 - 虚继承不影响派生类是否能访问基类成员(访问权限仍由
public/protected/private决定) - 虚基类不能是前置声明类型(即
class A;不够,必须有完整定义),否则编译失败
什么时候必须用virtual析构函数
只要类设计为被继承、且预期用户会用基类指针管理派生类对象(比如工厂函数返回 Base*),就必须把析构函数声明为 virtual。
否则,delete ptr_to_base 只会调用基类析构函数,派生类部分的资源(如堆内存、文件句柄)不会释放 —— 典型内存泄漏源头。
- 纯虚析构函数可以有定义:
virtual ~Base() = 0 { },否则链接时报错 - 如果类不含任何
virtual函数,又没打算被继承,就不该加virtual析构函数,避免无谓开销 - 现代 C++ 更倾向用智能指针(如
std::unique_ptr<base>),但virtual析构仍是底层保障
虚函数机制依赖 vtable,虚继承引入虚基类表(vbtable),两者都增加对象尺寸和间接访问成本。用不用,得看是否真需要多态或解决菱形继承,而不是“看起来高级”。











