假设你有一个万能遥控器,上面只有一个“开关”按钮:
C++中的虚函数(Virtual Function) 就像这个“智能按钮”,允许基类指针在运行时动态调用子类的具体实现。今天,我们就来揭开虚函数的神秘面纱!
虚函数是C++实现运行时多态的核心机制,通过在基类中用 virtual
关键字声明,允许子类重写(Override)该函数。
class Device {
public:
virtual void turnOn() { // 虚函数
cout << "设备启动" << endl;
}
};
class TV : public Device {
public:
void turnOn() override { // 重写虚函数
cout << "电视开机,播放欢迎画面" << endl;
}
};
class AC : public Device {
public:
void turnOn() override {
cout << "空调开始制冷" << endl;
}
};
// 使用基类指针调用不同子类的方法
Device* device1 = new TV();
Device* device2 = new AC();
device1->turnOn(); // 输出电视开机
device2->turnOn(); // 输出空调制冷
当通过基类指针调用虚函数时:
class Base {
public:
virtual void func1() {}
virtual void func2() {}
int data;
};
Base obj;
obj
的内存结构:| vptr | data |
↑指向Base的vtable(存储func1和func2的地址)
基类的析构函数必须声明为虚函数,否则通过基类指针删除子类对象时,只会调用基类析构函数,导致子类资源泄漏!
class Base {
public:
virtual ~Base() { // 虚析构函数
cout << "释放Base资源" << endl;
}
};
class Derived : public Base {
public:
~Derived() override {
cout << "释放Derived资源" << endl;
}
};
Base* obj = new Derived();
delete obj;
// 输出:
// 释放Derived资源
// 释放Base资源
= 0
标记。class Shape { // 抽象类
public:
virtual double area() const = 0; // 纯虚函数
};
class Circle : public Shape {
public:
double area() const override {
return 3.14 * radius * radius;
}
private:
double radius;
};
override
明确重写(C++11)class Derived : public Base {
public:
void func() override { // 显式声明重写
// ...
}
};
final
禁止重写(C++11)class Base {
public:
virtual void lock() final {} // 禁止子类重写
};
class Derived : public Base {
public:
void lock() override {} // 编译错误!
};
在构造函数中,虚函数机制未完全建立,调用虚函数会执行基类版本:
class Base {
public:
Base() { init(); }
virtual void init() { cout << "Base init" << endl; }
};
class Derived : public Base {
public:
void init() override { cout << "Derived init" << endl; }
};
Derived d; // 输出"Base init",而非"Derived init"
将子类对象赋值给基类对象时,会发生“切片”,丢失子类特有数据:
Derived d;
Base b = d; // 仅复制Base部分,Derived部分被“切掉”
虚函数通过动态绑定机制,让代码灵活适应不同类型的对象,是面向对象设计的核心工具。
下次当你写下 virtual
关键字时,不妨想象自己正在为代码注入“智能基因”——让程序在运行时自主选择最佳行为!
(完)
希望这篇博客能帮助读者深入理解虚函数的精髓!如果需要补充示例或调整内容,请随时告诉我~