c++中virtual关键字用法_c++虚基类作用【详解】

2次阅读

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

c++中virtual关键字用法_c++虚基类作用【详解】

virtual函数怎么写才真正起作用

只有在基类中用 virtual 声明的成员函数,派生类里用相同签名(函数名、参数类型、const 限定)重写时,才能实现运行时多态。光在派生类加 virtual 没用,基类没标就只是普通重载。

常见错误:漏掉 const 或引用修饰符,导致函数签名不一致,编译器认为是新函数而非重写 —— 这时调用仍走基类版本,virtual 形同虚设。

  • 必须在基类声明处加 virtual,派生类可加可不加(c++11 起推荐加 override 显式标记)
  • 返回类型需协变(如基类返回 Base*,派生类可返回 Derived*),否则编译报错
  • 构造函数不能是 virtual析构函数建议声明为 virtual,尤其当对象可能通过基类指针删除时

虚基类解决的是什么问题

多重继承中,若两个父类都继承自同一个祖父类,子类默认会包含两份该祖父类的子对象 —— 导致二义性(比如调用祖父类函数时编译器不知道选哪份)和内存冗余。虚基类强制让这个公共祖先只被继承一次。

典型场景:class A 是根,class B : virtual public Aclass C : virtual public A,再有 class D : public B, public C —— 此时 D 中只有一个 A 子对象。

立即学习C++免费学习笔记(深入)”;

  • 关键字 virtual 必须出现在**最直接继承路径**上(即 BC 的继承列表里),在 D 里补没用
  • 虚基类的构造函数由**最派生类**(这里是 D)负责调用,BC 的构造函数里对 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),两者都增加对象尺寸和间接访问成本。用不用,得看是否真需要多态或解决菱形继承,而不是“看起来高级”。

text=ZqhQzanResources