不算。只要基类中所有纯虚函数都提供了函数体(哪怕仅{}),该类就不再是抽象类;语法上仍称纯虚函数,但语义上已失效,c++标准允许=0后直接写函数体。

不算。只要基类里所有纯虚函数都提供了定义(哪怕只有一行 {}),它就不再是抽象类。
纯虚函数写了函数体,还叫“纯虚”吗
语法上依然叫纯虚函数,但语义上已失效。C++ 标准允许在声明为 = 0 的纯虚函数后直接写函数体,例如:
virtual void draw() const = 0 {
std::cout
<p>这种写法合法(C++11 起),但关键点在于:<strong>它不再强制派生类必须重写</strong>。派生类可以不实现 <code>draw()</code>,也能实例化对象。</p>
- 编译器不会报错:派生类未重写该函数 → 不再是抽象类
- 运行时调用该函数:若派生类没重写,会执行基类中这个带函数体的版本
- 这本质上退化成了“有默认实现的虚函数”,和普通虚函数行为一致
为什么有人误以为“写了实现就不是纯虚函数了”
因为常见教材和初学者示例里,纯虚函数几乎总是写成 virtual void f() = 0; 后面不跟 {}。一旦加了函数体,就容易混淆概念边界:
-
= 0是“纯虚”的语法标记,不是“禁止实现”的禁令 - 是否抽象类,只取决于“有没有未实现的纯虚函数”,而不是“有没有写
= 0” - 如果一个类所有虚函数(含带函数体的
= 0函数)都有可调用的定义,它就能被new或栈上构造
纯虚析构函数必须实现,但它不影响抽象性
这是唯一必须写函数体的纯虚函数,但它的存在本身仍会让类成为抽象类:
virtual ~Base() = 0; // 声明纯虚析构
Base::~Base() {} // 必须定义,否则链接失败
- 即使你实现了
~Base(),只要还有别的纯虚函数没实现,Base仍是抽象类 - 只实现析构函数,不实现其他纯虚函数 → 派生类依然不能实例化
- 析构函数的特殊性在于:它必须可调用,否则派生类析构时无法链式调用基类析构
怎么快速判断一个类是不是抽象类
别看有没有 = 0,直接试构造:
- 写
Base b;编译失败?→ 抽象类(至少一个纯虚函数没实现) - 错误信息含
cannot declare variable 'b' to be of abstract type或C2259?→ 确认哪些函数没被派生类覆盖 - 用
static_assert(!std::is_abstract_v<base>, "Base must be concrete");在编译期断言
最容易被忽略的是:带函数体的 = 0 函数,看起来像纯虚,实际已放弃强制契约;而纯虚析构函数必须实现,却丝毫不削弱其抽象地位。这两者方向相反,但都依赖同一个判断依据——是否“真正未实现”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











