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

纯虚函数怎么声明和定义
纯虚函数不是“必须写实现”,而是“必须在派生类里实现”,声明时用 = 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 时可能崩溃。










