1. 虚函数基础概念
1.1 什么是虚函数
虚函数是用 virtual 关键字声明的成员函数,它支持动态绑定,使得程序能在运行时根据对象的实际类型调用相应的函数。
class Base {
public:
virtual void show() { // 虚函数
cout << "Base::show()" << endl;
}
void display() { // 非虚函数
cout << "Base::display()" << endl;
}
};
class Derived : public Base {
public:
void show() override { // 重写虚函数
cout << "Derived::show()" << endl;
}
void display() { // 隐藏基类函数
cout << "Derived::display()" << endl;
}
};1.2 静态绑定 vs 动态绑定
int main() {
Derived d;
Base* ptr = &d;
Base& ref = d;
// 动态绑定(运行时决定)
ptr->show(); // 输出: Derived::show()
ref.show(); // 输出: Derived::show()
// 静态绑定(编译时决定)
ptr->display(); // 输出: Base::display()
ref.display(); // 输出: Base::display()
}2. 虚函数表(Virtual Table)机制
2.1 虚表的结构
class Base {
public:
virtual void func1() { cout << "Base::func1" << endl; }
virtual void func2() { cout << "Base::func2" << endl; }
virtual void func3() { cout << "Base::func3" << endl; }
void func4() { cout << "Base::func4" << endl; } // 非虚函数
private:
int base_data;
};
class Derived : public Base {
public:
void func1() override { cout << "Derived::func1" << endl; }
virtual void func5() { cout << "Derived::func5" << endl; }
private:
int derived_data;
};内存布局示意:
Base对象内存布局:
+----------+
| vptr | -----> Base虚表
+----------+ +----------------+
| base_data| | &Base::func1 |
+----------+ | &Base::func2 |
| &Base::func3 |
+----------------+
Derived对象内存布局:
+-------------+
| vptr | -----> Derived虚表
+-------------+ +------------------+
| base_data | | &Derived::func1 | (重写)
+-------------+ | &Base::func2 | (继承)
| derived_data| | &Base::func3 | (继承)
+-------------+ | &Derived::func5 | (新增)
+------------------+2.2 查看虚表内容(实验性代码)
#include <iostream>
#include <cstring>
using namespace std;
class Base {
public:
virtual void f() { cout << "Base::f" << endl; }
virtual void g() { cout << "Base::g" << endl; }
virtual void h() { cout << "Base::h" << endl; }
};
class Derived : public Base {
public:
void f() override { cout << "Derived::f" << endl; }
virtual void i() { cout << "Derived::i" << endl; }
};
// 函数指针类型
typedef void(*Fun)(void);
void printVTable(Base* obj, const string& className) {
cout << "=== " << className << " 虚表 ===" << endl;
// 获取vptr(虚表指针)
void** vptr = *(void***)obj;
// 遍历虚表
for (int i = 0; vptr[i] != nullptr && i < 10; i++) {
cout << "虚函数[" << i << "] 地址: " << vptr[i];
// 尝试调用(危险操作,仅用于演示)
Fun func = (Fun)vptr[i];
cout << " -> ";
func();
}
cout << endl;
}
int main() {
Base b;
Derived d;
printVTable(&b, "Base");
printVTable(&d, "Derived");
return 0;
}3. 虚函数的内部实现
3.1 虚函数调用过程
class Animal {
public:
virtual void makeSound() {
cout << "Animal sound" << endl;
}
};
class Dog : public Animal {
public:
void makeSound() override {
cout << "Woof!" << endl;
}
};
int main() {
Dog dog;
Animal* ptr = &dog;
// ptr->makeSound() 的实际执行过程:
// 1. 获取对象的vptr
// 2. 通过vptr找到虚表
// 3. 在虚表中找到makeSound的地址(通常是第一个槽位)
// 4. 调用该地址的函数
ptr->makeSound(); // 相当于: (*(ptr->vptr[0]))(ptr)
}3.2 汇编层面的实现(简化版)
; ptr->makeSound() 的汇编代码(简化)
mov rax, [ptr] ; 获取对象地址
mov rcx, [rax] ; 获取vptr(对象的第一个成员)
mov rdx, [rcx] ; 获取虚表中第一个函数地址
call rdx ; 调用虚函数4. 特殊情况和边界案例
4.1 构造函数中的虚函数
class Base {
public:
Base() {
cout << "Base构造函数" << endl;
callVirtual(); // 调用虚函数
}
virtual void callVirtual() {
cout << "Base::callVirtual" << endl;
}
virtual ~Base() {
cout << "Base析构函数" << endl;
callVirtual(); // 调用虚函数
}
};
class Derived : public Base {
public:
Derived() {
cout << "Derived构造函数" << endl;
callVirtual();
}
void callVirtual() override {
cout << "Derived::callVirtual" << endl;
}
~Derived() {
cout << "Derived析构函数" << endl;
callVirtual();
}
};
int main() {
Derived d;
// 输出:
// Base构造函数
// Base::callVirtual (注意:不是Derived版本)
// Derived构造函数
// Derived::callVirtual
// Derived析构函数
// Derived::callVirtual
// Base析构函数
// Base::callVirtual (注意:不是Derived版本)
}4.2 多重继承的虚表
class Base1 {
public:
virtual void f1() { cout << "Base1::f1" << endl; }
virtual void f2() { cout << "Base1::f2" << endl; }
};
class Base2 {
public:
virtual void g1() { cout << "Base2::g1" << endl; }
virtual void g2() { cout << "Base2::g2" << endl; }
};
class Derived : public Base1, public Base2 {
public:
void f1() override { cout << "Derived::f1" << endl; }
void g1() override { cout << "Derived::g1" << endl; }
virtual void h() { cout << "Derived::h" << endl; }
};
// Derived对象内存布局:
// +-------------+
// | vptr1 | -----> 第一个虚表(Base1相关)
// | Base1数据 |
// +-------------+
// | vptr2 | -----> 第二个虚表(Base2相关)
// | Base2数据 |
// +-------------+
// | Derived数据 |
// +-------------+4.3 虚继承的虚表
class Base {
public:
int base_data;
virtual void func() { cout << "Base::func" << endl; }
};
class Derived1 : virtual public Base {
public:
int d1_data;
void func() override { cout << "Derived1::func" << endl; }
};
class Derived2 : virtual public Base {
public:
int d2_data;
void func() override { cout << "Derived2::func" << endl; }
};
class Final : public Derived1, public Derived2 {
public:
int final_data;
void func() override { cout << "Final::func" << endl; }
};
// Final对象会有额外的vbptr(虚基类指针)来处理虚继承5. 虚函数的高级特性
5.1 纯虚函数和抽象类
class Interface {
public:
// 纯虚函数
virtual void method1() = 0;
virtual int method2(int x) = 0;
// 纯虚函数也可以有实现
virtual void method3() = 0;
};
// 纯虚函数的实现(可选)
void Interface::method3() {
cout << "Interface::method3 default implementation" << endl;
}
class Concrete : public Interface {
public:
void method1() override {
cout << "Concrete::method1" << endl;
}
int method2(int x) override {
return x * 2;
}
void method3() override {
Interface::method3(); // 可以调用纯虚函数的实现
cout << "Concrete::method3" << endl;
}
};5.2 虚析构函数
class Base {
public:
Base() { data = new int[100]; }
// 虚析构函数非常重要!
virtual ~Base() {
delete[] data;
cout << "Base析构" << endl;
}
private:
int* data;
};
class Derived : public Base {
public:
Derived() { extra = new int[200]; }
~Derived() {
delete[] extra;
cout << "Derived析构" << endl;
}
private:
int* extra;
};
int main() {
Base* ptr = new Derived();
delete ptr; // 正确调用Derived和Base的析构函数
}6. 性能分析和优化
6.1 虚函数的开销
#include <chrono>
using namespace std::chrono;
class Test {
public:
// 非虚函数
int normalFunc(int x) { return x * 2; }
// 虚函数
virtual int virtualFunc(int x) { return x * 2; }
// 内联函数
inline int inlineFunc(int x) { return x * 2; }
};
void performanceTest() {
Test obj;
Test* ptr = &obj;
const int iterations = 100000000;
// 测试非虚函数
auto start = high_resolution_clock::now();
for (int i = 0; i < iterations; i++) {
ptr->normalFunc(i);
}
auto end = high_resolution_clock::now();
cout << "非虚函数: "
<< duration_cast<milliseconds>(end - start).count()
<< "ms" << endl;
// 测试虚函数
start = high_resolution_clock::now();
for (int i = 0; i < iterations; i++) {
ptr->virtualFunc(i);
}
end = high_resolution_clock::now();
cout << "虚函数: "
<< duration_cast<milliseconds>(end - start).count()
<< "ms" << endl;
}6.2 优化技巧
// 1. 使用final避免虚函数调用
class Optimized final : public Base {
public:
void func() override final { // 编译器可以优化
// ...
}
};
// 2. 避免在热路径中使用虚函数
class GameObject {
public:
// 热路径函数不要设为虚函数
void update(float deltaTime) {
updatePosition(deltaTime); // 非虚
updatePhysics(deltaTime); // 非虚
onSpecialEvent(); // 虚函数,偶尔调用
}
protected:
void updatePosition(float dt) { /* ... */ }
void updatePhysics(float dt) { /* ... */ }
virtual void onSpecialEvent() { }
};
// 3. 使用CRTP(奇异递归模板模式)实现静态多态
template<typename Derived>
class Base {
public:
void interface() {
static_cast<Derived*>(this)->implementation();
}
};
class DerivedCRTP : public Base<DerivedCRTP> {
public:
void implementation() {
cout << "静态多态实现" << endl;
}
};7. 完整示例:模拟虚表机制
#include <iostream>
#include <vector>
#include <functional>
#include <map>
using namespace std;
// 模拟虚表的简化实现
class VirtualTable {
public:
vector<void*> functions;
void addFunction(void* func) {
functions.push_back(func);
}
void* getFunction(int index) {
if (index < functions.size()) {
return functions[index];
}
return nullptr;
}
};
// 模拟带虚函数的类
class SimulatedBase {
public:
VirtualTable* vptr; // 虚表指针
int data;
SimulatedBase() : data(10) {
// 设置虚表
static VirtualTable vtable;
static bool initialized = false;
if (!initialized) {
vtable.addFunction((void*)&SimulatedBase::func1_impl);
vtable.addFunction((void*)&SimulatedBase::func2_impl);
initialized = true;
}
vptr = &vtable;
}
// 虚函数调用包装器
void func1() {
typedef void(*Func)(SimulatedBase*);
Func f = (Func)vptr->getFunction(0);
f(this);
}
void func2() {
typedef void(*Func)(SimulatedBase*);
Func f = (Func)vptr->getFunction(1);
f(this);
}
private:
static void func1_impl(SimulatedBase* self) {
cout << "Base::func1, data = " << self->data << endl;
}
static void func2_impl(SimulatedBase* self) {
cout << "Base::func2, data = " << self->data << endl;
}
};
class SimulatedDerived : public SimulatedBase {
public:
int derived_data;
SimulatedDerived() : derived_data(20) {
// 替换虚表
static VirtualTable vtable;
static bool initialized = false;
if (!initialized) {
vtable.addFunction((void*)&SimulatedDerived::func1_impl);
vtable.addFunction((void*)&SimulatedBase::func2_impl);
initialized = true;
}
vptr = &vtable;
}
private:
static void func1_impl(SimulatedBase* self) {
SimulatedDerived* derived = static_cast<SimulatedDerived*>(self);
cout << "Derived::func1, data = " << derived->data
<< ", derived_data = " << derived->derived_data << endl;
}
};
int main() {
cout << "=== 模拟虚表机制 ===" << endl;
SimulatedBase base;
SimulatedDerived derived;
SimulatedBase* ptr = &base;
ptr->func1(); // Base::func1
ptr->func2(); // Base::func2
ptr = &derived;
ptr->func1(); // Derived::func1
ptr->func2(); // Base::func2
return 0;
}8. 调试技巧
8.1 查看对象的虚表
// GDB调试命令
// (gdb) info vtbl object_name
// (gdb) p /a *(void**)object_ptr
// Visual Studio调试
// 在监视窗口中查看 *(void**)&object8.2 运行时类型信息(RTTI)
#include <typeinfo>
class Base {
public:
virtual ~Base() = default;
};
class Derived : public Base {};
void checkType(Base* ptr) {
// 使用typeid
cout << "类型: " << typeid(*ptr).name() << endl;
// 使用dynamic_cast
if (Derived* d = dynamic_cast<Derived*>(ptr)) {
cout << "是Derived类型" << endl;
} else {
cout << "不是Derived类型" << endl;
}
}虚函数和虚表是C++实现运行时多态的核心机制。理解其原理有助于写出更高效、更安全的代码。