Bootstrap

C++ 多态 虚函数

C++多态与虚函数

一、虚函数基础

1. 概念定义

  • 虚函数:用virtual关键字声明的成员函数
  • 核心作用:实现运行时多态,允许派生类重写基类方法
  • 调用特性:通过基类指针/引用调用时,根据实际对象类型决定调用版本

2. 定义格式

cpp

class Base {
public:
    virtual ReturnType funcName(ParameterList); 
    // 虚函数声明
};

3. 函数重写要求

  • 三同原则:
    1. 函数名相同
    2. 参数列表相同
    3. 返回类型相同(C++11允许协变返回类型)

二、多态实现三要素

  1. 继承关系:存在继承体系的类层次结构
  2. 虚函数重写:派生类重写基类虚函数
  3. 基类指针/引用:使用基类类型的指针或引用操作派生类对象

三、纯虚函数与抽象类

1. 定义格式

cpp

virtual ReturnType funcName() = 0;

2. 核心特性

  • 使类成为抽象类(不可实例化)
  • 强制派生类必须实现该接口
  • 典型应用场景:
    • 定义接口规范
    • 创建通用基类模板

四、虚函数表机制

1. 实现原理

  • vtable:编译器为含虚函数的类生成的函数指针数组
  • vptr:每个对象隐含的指向vtable的指针(通常位于对象起始位置)

2. 继承体系中的表现

继承类型vtable特性
单继承派生类vtable包含基类vtable内容,重写函数覆盖基类条目
多继承派生类维护多个vtable(对应每个基类),重写函数更新所有相关条目

五、特殊函数处理

1. 虚析构函数

cpp

class Base {
public:
    virtual ~Base() {} // 虚析构函数声明
};
  • 必要性:确保通过基类指针删除派生类对象时正确调用完整析构链
  • 内存安全:防止派生类资源泄漏

2. 限制说明

构造函数

  • 不能为虚函数(对象构造时vptr尚未初始化)

  • 不能声明为virtual

友元函数

  • 不属于类成员,不能声明为虚函数

六、现代C++特性

1. override关键字

cpp

class Derived : public Base {
    void func() override; // 显式声明重写
};
  • 作用:显式标记函数重写,增强代码可读性
  • 优势:编译器检查重写有效性,避免签名错误

2. final关键字

cpp

class Base {
    virtual void func() final; // 禁止派生类重写
};

class Derived final {}; // 禁止继续继承
  • 类级使用:禁止类被继承
  • 函数级使用:禁止虚函数被重写

七、关键注意事项

  1. 运行时成本:虚函数调用比普通函数多一次间接寻址(查vtable)

  2. 对象大小:每个含虚函数的对象增加一个指针大小(vptr)

构造/析构顺序

  • 构造函数中虚函数机制未完全建立
  • 析构函数中虚函数机制已部分销毁
  1. 接口设计:优先使用纯虚函数定义抽象接口

  2. 继承深度:建议不超过3层,避免过度复杂的继承体系

八、典型代码示例

cpp

// 抽象基类
class Shape {
public:
    virtual double area() const = 0; // 纯虚函数
    virtual ~Shape() = default;      // 虚析构函数
};

class Circle : public Shape {
    double radius;
public:
    Circle(double r) : radius(r) {}
    double area() const override {   // 实现纯虚函数
        return 3.14159 * radius * radius;
    }
};

// 使用示例
void printArea(const Shape& shape) {
    cout << "Area: " << shape.area(); // 多态调用
}

int main() {
    Circle c(5.0);
    printArea(c);  // 输出正确的圆面积
    return 0;
}
;