8.C++虚函数

C++虚函数

虚函数是C++实现运行时多态的核心机制,它允许通过基类指针或引用调用派生类的实现。下面我将全面介绍虚函数的概念、工作原理和使用方法。

纯虚函数(无实现体)类似与Java中的接口,虚函数(有实现体)类似与Java中的抽象方法。

1.虚函数基本感念

1.1定义与声明

使用virtual关键字来定义与声明成员函数

class Base {
public:
    virtual void show() {  // 虚函数声明
        cout << "Base show()" << endl;
    }
};

class Derived : public Base {
public:
    void show() override {  // 派生类重写
        cout << "Derived show()" << endl;
    }
};

1.2虚函数调用

通过基类指针或引用调用时,实际执行的是对象类型的版本:

Base* b = new Derived();
b->show();  // 输出"Derived show()"

2.虚函数的工作原理

2.1 虚函数表(vtable)

  • 每个包含虚函数的类都有一个虚函数表
  • 表中存放该类所有虚函数的地址
  • 对象中包含指向vtable的指针(vptr)

2.2 内存结构示例

Derived 对象:
+----------------+
| vptr           | --> Derived的vtable
| Base成员变量    |    +----------------+
| Derived成员变量 |    | &Derived::show |
+----------------+    +----------------+

3. 虚函数关键特性

3.1 覆盖(override)

派生类可以重写基类的虚函数:

class Animal {
public:
    virtual void speak() {
        cout << "Animal sound" << endl;
    }
};

class Dog : public Animal {
public:
    void speak() override {  // 明确表示覆盖
        cout << "Woof!" << endl;
    }
};

3.2 纯虚函数

使类成为抽象基类:

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

// 必须实现才能实例化
class Circle : public Shape {
public:
    void draw() override {
        cout << "Drawing circle" << endl;
    }
};

4. 虚函数使用场景

4.1 多态容器

vector<Animal*> zoo;
zoo.push_back(new Dog());
zoo.push_back(new Cat());

for (auto animal : zoo) {
    animal->speak();  // 调用各自实现
}

4.2 工厂模式

class Product {
public:
    virtual void use() = 0;
};

class ConcreteProduct : public Product {
    void use() override { /*...*/ }
};

Product* createProduct() {
    return new ConcreteProduct();
}

5. 高级特性

5.1 虚析构函数

确保正确调用派生类析构函数:

class Base {
public:
    virtual ~Base() {}  // 虚析构函数
};

class Derived : public Base {
public:
    ~Derived() override { /* 清理资源 */ }
};

Base* b = new Derived();
delete b;  // 正确调用Derived的析构函数

5.2 final关键字

禁止进一步覆盖:

class Base {
public:
    virtual void foo() final {}  // 禁止派生类覆盖
};

class Derived : public Base {
    // void foo() override {}  // 错误!不能覆盖final函数
};

6. 性能考虑

  • 虚函数调用比普通函数多一次间接寻址
  • 每个对象需要额外空间存储vptr
  • 不适合在性能关键代码中过度使用

7. 最佳实践

  1. 多态基类的析构函数应该声明为虚函数
  2. 使用override明确表示覆盖意图
  3. 接口类使用纯虚函数
  4. 合理使用final优化设计
  5. 避免在构造函数/析构函数中调用虚函数

虚函数是C++面向对象编程的强大工具,正确使用可以实现灵活的多态设计,但也需要注意其开销和适用场景。

posted @ 2025-06-27 20:05  站着说话不腰疼  阅读(210)  评论(0)    收藏  举报