C++怎么使用纯虚函数_C++抽象类教程【接口】

纯虚函数声明为virtual void func() = 0;,不可有函数体;含纯虚函数的类为抽象类,不可实例化,仅可作基类;派生类未实现所有纯虚函数则仍为抽象类。

C++怎么使用纯虚函数_C++抽象类教程【接口】

纯虚函数怎么声明和定义

纯虚函数不是“必须写实现”,而是“必须在派生类里实现”,声明时用 = 0 结尾,且不能有函数体。常见错误是加了花括号、写了空实现,或者漏掉 = 0 导致编译器不认为它是纯虚函数。

  • virtual void draw() = 0; ✅ 正确声明
  • virtual void draw() { } ❌ 变成普通虚函数,基类可实例化
  • virtual void draw() = 0 { } ❌ 语法错误,= 0 和函数体互斥
  • 纯虚函数可以有声明无定义,但若意外写了定义(比如在类外),链接时可能报 undefined reference

抽象类为什么不能实例化

只要类中有一个纯虚函数,它就是抽象类;抽象类本质是“契约模板”,不是用来干活的。试图 Base b;new Base() 会触发编译错误,典型提示是 cannot declare variable 'b' to be of abstract type 'Base'

  • 抽象类只能作为指针或引用类型使用:Base* p = new Derived();
  • 即使所有纯虚函数都被派生类覆盖,抽象类本身仍不可实例化
  • 构造函数/析构函数可以存在,但析构函数建议声明为 virtual ~Base() = 0; 并提供定义(否则派生类析构可能不安全)

派生类没重写纯虚函数会怎样

如果派生类继承了抽象类但没实现全部纯虚函数,它自己也自动变成抽象类——依然不能实例化。这个行为常被忽略,尤其在多层继承或接口拆分时。

  • 错误现象:error: cannot declare variable 'd' to be of abstract type 'Derived'
  • 检查方式:用 IDE 跳转或 grep 搜索未实现的 virtual ... = 0 函数名
  • 注意 const 限定符差异:virtual void func() const = 0;void func() 不构成重写,会导致派生类仍抽象
  • 返回类型协变允许微调(如基类返回 Base*,派生类返回 Derived*),但签名主体必须一致

纯虚函数 vs 接口模拟(比如 Java interface)

C++ 没有 interface 关键字,纯虚函数是主要手段,但要注意它不等于 Java 的 interface:C++ 抽象类可含数据成员、非虚函数、构造函数,而 Java interface 默认全是 public abstract 方法(Java 8+ 才支持 default/static 方法)。

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

  • 想模拟“纯接口”,就只放 public: 下的纯虚函数,不加成员变量和实现
  • 多重继承抽象类没问题,但要注意菱形继承问题,必要时用 virtual 继承
  • 性能上无额外开销——纯虚函数仍是虚函数表调用,和普通虚函数一样快
  • 头文件中定义纯虚函数不会导致 ODR 违反,但若误加 inline 实现,可能引发链接问题

最易被忽略的是析构函数:哪怕只声明 virtual ~Base() = 0;,也必须在 .cpp 文件里给出定义(哪怕空实现),否则派生类 delete 时可能崩溃。