抽象类必须包含至少一个纯虚函数(virtual func() = 0),否则可实例化;纯虚函数可带实现供派生类显式调用;析构函数若为纯虚则必须定义;不可构造对象,仅支持指针/引用实现多态。

抽象类必须包含至少一个纯虚函数
在 C++ 中,抽象类不是靠关键字声明的,而是由编译器根据类中是否含有 = 0 的成员函数自动判定。只要类中定义了至少一个纯虚函数,这个类就无法被实例化——哪怕其他所有函数都已实现。
常见错误是误以为加了 virtual 就是抽象类:virtual void func(); 只是虚函数,不加 = 0 就不算纯虚,类仍可实例化。
-
virtual void draw() = 0;→ 正确,强制子类重写 -
virtual void init();→ 不是纯虚,不影响抽象性 - 类中只有
= 0函数但没加virtual→ 编译报错:error: non-virtual function cannot be pure
纯虚函数可以有函数体,但不能直接调用
很多人以为 = 0 意味着“没实现”,其实 C++ 允许为纯虚函数提供定义(通常写在类外),供派生类通过作用域解析符显式调用。这在需要共享默认逻辑时很有用,比如日志、资源清理等。
注意:即使写了函数体,也不能通过基类对象或指针直接调用它(因为对象不存在);只能在派生类中用 Base::func() 形式调用。
立即学习“C++免费学习笔记(深入)”;
- 声明:
virtual void cleanup() = 0; - 定义:
void Base::cleanup() { /* 公共释放逻辑 */ } - 派生类中调用:
Base::cleanup();(合法) - 通过
Base* p = new Derived;然后p->cleanup();→ 调用的是派生类重写的版本,不是基类函数体
析构函数声明为纯虚时必须提供定义
如果把析构函数写成纯虚:virtual ~Base() = 0;,编译器会要求你必须在类外给出实现,否则链接失败。这是因为派生类析构时会隐式调用基类析构函数,而纯虚函数若无定义就无法链接。
这不是语法糖,是真实需求:确保多态销毁安全,同时避免基类被实例化。
- 必须写:
Base::~Base() {}或带实际清理逻辑 - 只声明不定义 → 链接错误:
undefined reference to 'Base::~Base()' - 构造函数不能是纯虚(语法不允许),也不该是虚函数
抽象类指针和引用是多态使用的唯一合法入口
抽象类不能定义对象,但可以定义指针或引用,这是使用抽象类的常规方式。所有运行时多态行为(如 virtual 函数动态绑定)都依赖于此。
容易忽略的一点是:抽象类的引用/指针本身不占额外内存开销,但其指向的对象必须完整构造(即派生类对象需满足虚表布局兼容性)。
-
Base* p = new Derived;→ 合法,p->draw()调用Derived::draw -
Base obj;→ 编译错误:instantiation of abstract class -
Base& ref = *new Derived;→ 合法,但要注意悬垂引用风险 - 返回抽象类对象的函数(如
Base create();)→ 编译不过,值返回会触发拷贝,而抽象类无拷贝构造
抽象类的核心约束不在语法糖,而在对象生命周期和虚函数表的底层协同。一旦忘记为纯虚析构函数提供定义,或者误用值传递/返回,问题往往出现在链接期或运行期崩溃,而不是编译提示。











