C++如何实现多态_C++接口类与纯虚函数定义规范【设计】

9次阅读

多态必须通过基类指针或引用触发,值传递导致对象切片和静态绑定;接口类须全虚函数+虚析构;override强制编译器检查重写正确性;虚表带来轻微内存开销。

C++如何实现多态_C++接口类与纯虚函数定义规范【设计】

多态必须靠指针或引用才能触发

直接用对象值传递或局部变量声明,编译器会在编译期就绑定函数(静态绑定),virtualoverride 完全无效。只有通过基类指针或引用调用虚函数时,才会查虚表、走动态绑定。

  • ✅ 正确写法:Base* p = new Derived(); p->func();Base& ref = derived_obj; ref.func();
  • ❌ 错误写法:Base obj = Derived(); obj.func(); —— 这里发生对象切片,Derived 特有部分被丢弃,只剩 Base 子对象
  • 注意:std::unique_ptrstd::shared_ptr 同样支持多态,且更安全

接口类必须只含纯虚函数和析构函数

所谓“接口类”,本质是契约定义,不提供实现、不维护状态。c++ 中没有 interface 关键字,靠全纯虚函数 + 显式虚析构实现。

  • 纯虚函数写法统一用 = 0,不能带函数体:virtual void draw() = 0;
  • 必须声明虚析构函数:virtual ~Shape() = default;virtual ~Shape() {},否则 delete 派生类指针时析构不完整
  • 禁止在接口类中定义非静态数据成员、普通函数、构造函数(除默认/虚析构外)
  • 若需默认行为,应拆成抽象基类(含部分实现)+ 接口类(仅契约),不要混用

override 是强制检查,不是可选项

override 不只是语义提示,它让编译器验证:该函数是否真的重写了基类的虚函数。漏写或拼错签名会导致意外的重载而非重写,多态失效却无报错。

  • 基类函数没加 virtual子类override 直接编译失败
  • 参数类型不一致(比如 const int* vs int*)、const 修饰位置不同、返回类型协变没满足条件,都会触发错误
  • 现代项目应开启编译器警告(如 -Woverloaded-virtual/we4263),配合 override 形成双重保险

虚函数表开销小但不可忽视

每个含虚函数的类对象隐式携带一个指向虚表的指针(通常 8 字节,64 位平台),虚表本身存于只读段,大小取决于虚函数个数。对内存极度敏感的场景(如嵌入式、高频小对象池)要权衡。

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

  • 空接口类(全纯虚 + 虚析构)的对象大小仍是 sizeof(void*),不是 0
  • 多重继承下虚表更复杂,可能产生多个虚表指针,sizeof 可能翻倍
  • 若确定无需运行时多态,优先用模板 + concept(C++20)或策略模式替代虚函数,零成本抽象

虚析构函数的写法、override 的强制性、以及值语义导致的切片问题,这三点在真实项目里最容易被跳过或误判——尤其是当测试用例只覆盖了“看起来能跑通”的路径时。

text=ZqhQzanResources