定义不能被实例化,但能用作基类的抽象类型。
语法
纯虚 (pure virtual) 函数是声明器拥有下列语法的虚函数:
declarator virt-specifier(可选) = 0 | |||||||||
此处序列 = 0
被称作 pure-specifier ,且立即出现于 declarator 后或于可选的 virt-specifier ( override 或 final )后。
pure-specifier 不能出现于成员函数定义中。
struct Base { virtual int g(); virtual ~Base() {} };
struct A : Base{
// OK :声明三个成员虚函数,其二为纯
virtual int f() = 0, g() override = 0, h();
// OK :析构函数亦能为纯
~A() = 0;
// 错误:纯指定符在函数定义上
virtual int b()=0 {}
};
abstract class 是定义或继承了至少一个最终覆写为 pure virtual 的函数的类。
解释
抽象类用于表示通用概念(例如 Shape 、 Animal ),它可用作具体类(例如 Circle 、 Dog )的基类。
不能创建抽象类的实例。抽象类型不能用作参数类型、函数返回类型或显式转换的类型。可以声明到抽象类的指针或引用。
struct Abstract {
virtual void f() = 0; // 纯虚
}; // "Abstract" 为抽象
struct Concrete : Abstract {
void f() override {} // 非纯虚
virtual void g(); // 非纯虚
}; // "Concrete" 为非抽象
struct Abstract2 : Concrete {
void g() override = 0; // 纯虚覆写
}; // "Abstract2" 为抽象
int main()
{
// Abstract a; // 错误:抽象类
Concrete b; // OK
Abstract& a = b; // OK :到抽象基类的引用
a.f(); // 到 Concrete::f() 的虚派发
// Abstract2 a2; // 错误:抽象类( g() 的最终覆写为纯)
}
可以提供纯虚函数的定义(而且若析构函数为纯虚则必须提供):导出类的成员函数可以自由地用有限定函数 id 调用虚基类的纯虚函数。此定义必须在类体外(函数声明的语法不允许纯虚指定符 = 0
和函数体一起出现)。
从抽象类的构造函数或析构函数进行纯虚函数的虚调用是未定义行为(无论纯虚函数是否拥有定义)。
struct Abstract {
virtual void f() = 0; // 纯虚
virtual void g() {} // 非纯虚
~Abstract() {
g(); // OK :调用 Abstract::g()
// f(); // 未定义行为!
Abstract::f(); // OK :非虚调用
}
};
// 纯虚函数的定义
void Abstract::f() { std::cout << "A::f()\n"; }
struct Concrete : Abstract {
void f() override {
Abstract::f(); // OK :调用纯虚函数
}
void g() override {}
~Concrete() {
g(); // OK :调用 Concrete::g()
f(); // OK :调用 Concrete::f()
}
};