C++ 虚继承,虚函数与纯虚函数整理

OrzMiku / 2023-08-20 / 原文

1. 虚继承

虚继承是用于解决多继承中“菱形继承”问题的一种技术。在多继承中,如果两个基类都继承了同一个基类,派生类会包含两份该基类的数据成员和函数成员,从而产生冗余和二义性。虚继承的作用就是消除这种冗余。

虚继承的定义方式是在继承关系中添加关键字“virtual”,如下所示:

class A {
public:
    int a;
};

class B : virtual public A {
public:
    int b;
};

class C : virtual public A {
public:
    int c;
};

class D : public B, public C {
public:
    int d;
};

在上面的代码中,B 和 C 都使用了虚继承来继承 A。这样在 D 中,只有一份 A 的数据成员和函数成员,避免了冗余和二义性的问题。

需要注意的是,虚继承会导致派生类的内存布局发生变化,从而影响程序的性能和空间占用。因此,在使用虚继承时需要仔细考虑继承关系和设计。

2. 虚函数

虚函数是指在基类中声明的函数,在派生类中可以重新定义并赋予新的功能,使得派生类的对象调用该函数时能够根据对象的实际类型动态地绑定到相应的函数实现上。该特性被称为多态,是面向对象编程的重要特点之一。

虚函数的定义方式是在函数声明前添加关键字“virtual”,如下所示:

class A {
public:
    virtual void func() {}
};

派生类可以覆盖基类的虚函数,方法是在函数定义前使用相同的函数签名定义一个函数,如下所示:

class B : public A {
public:
    void func() {}
};

当调用一个虚函数时,编译器会根据对象的实际类型确定要调用的函数版本。例如:

A* ptr = new B;
ptr->func(); // 调用 B::func,而不是 A::func

3. 纯虚函数

纯虚函数是一个在基类中声明的没有实现的虚函数,通常用于定义抽象接口或者抽象类。我们可以通过在函数声明后面加上 "= 0",来将一个普通的虚函数变成一个纯虚函数。如下所示:

class Base {
public:
    virtual void func() = 0; // 纯虚函数声明
};

这个语法告诉编译器 func() 函数是一个纯虚函数,因此它必须在任何派生类中被实现。一个类如果包含纯虚函数,那么它就是一个抽象类,不能被直接实例化。

class Derived : public Base {
public:
    void func() override {} // 派生类必须实现纯虚函数
};

当我们派生一个子类时,必须重写基类的纯虚函数,否则子类也会成为抽象类。下面是一个例子:

class Shape {
public:
    virtual void draw() = 0; // 纯虚函数
};

class Circle : public Shape {
public:
    void draw() override {
        // 实现 draw() 的具体操作
    }
};

class Square : public Shape {
public:
    void draw() override {
        // 实现 draw() 的具体操作
    }
};

在上面的例子中,Shape 类是一个抽象类,它只声明了纯虚函数 draw(),子类 Circle 和 Square 继承了 Shape,必须实现 draw() 函数。这种方式可以实现多态性,通过 Shape 的指针或者引用调用派生类重写的函数。