抽象类

< cpp‎ | language

定义不能被实例化,但可用作基类的抽象类型。

语法

纯虚函数是其声明符拥有下列语法的虚函数

声明符 虚说明符(可选) = 0

此处序列 = 0 被称作 纯说明符,且要么紧跟 声明符 之后,要么紧跟可选的 虚说明符overridefinal)之后出现。

纯说明符 不能出现于成员函数定义中。

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) 是定义或继承了至少一个最终覆盖函数纯虚 的函数的类。

解释

抽象类用于表示一般性概念(例如 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() 的最终覆盖函数为纯虚)
}

可以为纯虚函数提供定义(而且若纯虚函数是析构函数则必须提供):派生类的成员函数可以自由地用有限定的函数表示调用抽象基类的纯虚函数。此定义必须在类体之外提供(函数声明的语法不允许纯说明符 = 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()
    }
};

参阅