纯虚函数声明为“= 0”即表示无实现,编译期契约不可违背;即便类外定义了同名函数,也不改变其纯虚性质,不能被默认调用。

因为“纯虚函数已实现”这个说法本身就不成立——只要声明了 = 0,它就是纯虚函数,编译器就认为它没有(或不许你依赖)实现,哪怕你在类外偷偷加了定义。
纯虚函数的 = 0 是编译期契约,不是语法糖
很多人看到如下代码就误以为“实现了”:
class Shape {
public:
virtual void draw() const = 0;
};
void Shape::draw() const { std::cout
<p>这确实能编译通过,但 <code>Shape</code> 仍是抽象类,<code>Shape s;</code> 依然报错:<code>error: variable type 'Shape' is an abstract class</code>。原因很直接:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
-
= 0告诉编译器:“这个函数不提供可调用的默认行为”,编译器据此标记该类为抽象类 - 类外定义只是“技术上合法”,但它不改变
= 0所触发的抽象类判定逻辑 - 运行时若真调用了未被派生类覆盖的纯虚函数(比如通过基类指针误调),程序会直接终止(典型错误是
Pure virtual function called)
哪些情况看似“实现了”,实则无效
以下写法都**不能解除抽象类限制**:
- 在类内写
virtual void f() = 0 { }—— 语法错误,= 0和函数体互斥 - 在类外定义
void Base::f() { ... }—— 编译过,但不影响实例化能力 - 用
override在基类里重写自己 —— 不合法,基类不能override自己的函数 - 把纯虚函数改成虚函数再加空实现:
virtual void f() { }—— 这时类就不再是抽象类了,但已不是纯虚函数
想让类可实例化?只有一条路:删掉所有 = 0
如果你发现某个类“明明写了实现却不能 new”,大概率是没看清声明位置。检查点包括:
- 确认所有含
= 0的函数都被移除了,或改成了带函数体的虚函数 - 注意多继承场景:只要任一父类留有未实现的纯虚函数,派生类仍是抽象类
- 别忽略析构函数 ——
virtual ~Base() = 0;也足以让类变抽象;即使你类外实现了它,也得补上Base::~Base() { },且必须显式定义(否则链接失败)
最常被忽略的一点:纯虚函数的“可实现性”和“可实例化性”完全解耦。你可以给它写实现,但只要 = 0 还在,编译器就认定“这个类还没承诺能干活”,就不会放行 new 或栈对象构造。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










