抽象类

来自cppreference.com
< 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()
    }
};

参阅