纯虚函数是C++中通过virtual void func() = 0;语法声明的无实现成员函数,强制派生类必须精确重写(含const、参数、返回类型),否则仍为抽象类且无法实例化,编译期即报错。

什么是纯虚函数,它为什么能强制子类实现
纯虚函数是 C++ 中让基类成为抽象类、同时要求派生类必须重写某个接口的机制。它不提供实现,只声明接口,编译器会在子类未实现时直接报错,而不是运行时报错或静默忽略。
- 纯虚函数定义形式为:
virtual void func() = 0; - 含纯虚函数的类无法实例化,即不能写
Base b;,否则编译失败 - 子类只要没实现所有纯虚函数,就仍是抽象类,也不能实例化
- 和普通虚函数不同,纯虚函数不要求基类有实现(即使写了,也得用
Base::func()显式调用)
如何正确声明和使用纯虚函数
关键在语法细节和继承链中的行为一致性:
- 必须用
virtual+= 0,缺一不可;写成virtual void f() {}是普通虚函数,不强制重写 - 函数签名(包括 const 限定、参数类型、返回类型)必须完全一致,否则不算重写,子类里那个函数只是新函数
- 如果基类纯虚函数是
virtual int get() const = 0;,子类必须也声明为const,否则编译报错:"invalid covariant return type" 或 "does not override" - 可以有默认实现(C++11 起允许),但调用仍需显式写
Base::func(),不影响强制重写要求
class Shape {
public:
virtual double area() const = 0; // 强制子类提供面积计算
virtual ~Shape() = default;
};
<p>class Circle : public Shape {
public:
double area() const override { return 3.14 <em> r </em> r; } // ✅ 正确重写
private:
double r = 1.0;
};</p>常见错误:以为写了函数体就“满足了要求”
很多初学者误以为只要子类里有个同名函数,就算实现了纯虚函数——实际不是,编译器只认精确匹配的重写:
- 忘记加
const:基类是virtual void draw() const = 0;,子类写void draw() { ... }→ 编译失败,提示未实现纯虚函数 - 参数类型不一致:比如基类是
virtual void set(int x) = 0;,子类写void set(long x)→ 不算重写,仍是抽象类 - 返回类型协变出错:基类返回
Shape<em></em>,子类想返回Circle,必须确保Circle继承自Shape,且声明为virtual Circle* clone() const = 0;才合法 - 用了
override却拼错函数名,比如aread()→ 编译器会报错说“no function declared in base class”,而不是“没实现纯虚函数”,容易误导
替代方案:编译期检查(static_assert + CRTP)适合什么场景
纯虚函数是运行期多态+编译期约束,但如果你不需要动态多态(比如不用 std::vector<std::unique_ptr<shape>></shape>),而只想在编译期确认子类提供了某函数,CRTP 更轻量:
立即学习“C++免费学习笔记(深入)”;
- 基类模板中用
static_cast<Derived*>(this)->func()触发调用,若子类没定义func,编译失败 - 错误信息通常比纯虚函数更直接(指向缺失函数定义处),但无法用于多态容器
- 不适用于需要运行时类型擦除的场景,比如插件系统、工厂模式
template<typename Derived>
class Drawable {
public:
void render() {
static_cast<Derived*>(this)->draw(); // 编译期查子类是否有 draw()
}
};
class MyWidget : public Drawable<MyWidget> {
public:
void draw() { /* OK */ } // ✅ 必须提供
};
纯虚函数的强制性只在“构造对象”那一刻才真正生效——哪怕你忘了实现,只要没 new 或 stack-allocate,链接和编译都可能通过。最容易被忽略的是:抽象类指针或引用本身合法,只有尝试实例化时才暴露问题,所以单元测试里漏掉构造子类实例,就可能把 bug 带到上线。


















