- 实现函数根据子类类型执行不同操作
#include <iostream>
class Base {
public:
virtual void doSomething() = 0;
virtual ~Base() {}
};
class Sub1 : public Base {
public:
void doSomething() override {
std::cout << "Sub1's doSomething" << std::endl;
}
};
class Sub2 : public Base {
public:
void doSomething() override {
std::cout << "Sub2's doSomething" << std::endl;
}
};
void performAction(Base* basePtr) {
if (Sub1* sub1Ptr = dynamic_cast<Sub1*>(basePtr)) {
sub1Ptr->doSomething();
} else if (Sub2* sub2Ptr = dynamic_cast<Sub2*>(basePtr)) {
sub2Ptr->doSomething();
}
}
- 内存管理避免内存泄漏
- 当使用
new
分配Base
及其子类对象时,在不再需要这些对象时,必须使用delete
来释放内存。如果通过Base
指针指向子类对象,要确保Base
类有虚析构函数,这样当通过Base
指针delete
对象时,会调用正确的子类析构函数来释放子类特有的资源。例如:
int main() {
Base* sub1 = new Sub1();
performAction(sub1);
delete sub1;
Base* sub2 = new Sub2();
performAction(sub2);
delete sub2;
return 0;
}
- 如果使用智能指针(如
std::unique_ptr
或std::shared_ptr
),可以更安全地管理内存。例如:
#include <memory>
int main() {
std::unique_ptr<Base> sub1 = std::make_unique<Sub1>();
performAction(sub1.get());
std::unique_ptr<Base> sub2 = std::make_unique<Sub2>();
performAction(sub2.get());
return 0;
}
- 虚函数表的结构和工作原理
- 结构:
- 每个包含虚函数(包括纯虚函数)的类都有一个虚函数表(vtable)。虚函数表是一个函数指针数组。
- 对于基类
Base
,虚函数表中存储了基类中虚函数的地址。如果基类有纯虚函数,虚函数表中对应的函数指针为nullptr
(在实际实现中可能有特定的标识)。
- 对于派生类,比如
Sub1
和Sub2
,它们的虚函数表首先复制基类的虚函数表内容,然后将重写的虚函数地址替换为派生类中该虚函数的实际地址。如果派生类有新的虚函数,这些函数的地址会追加到虚函数表的末尾。
- 工作原理:
- 当创建一个包含虚函数的类对象时,对象的内存布局中会有一个隐藏的指针(vptr),该指针指向该类的虚函数表。
- 当通过基类指针调用虚函数时,首先通过对象的vptr找到对应的虚函数表,然后根据虚函数在虚函数表中的索引找到实际要调用的函数地址,并执行该函数。例如,在
performAction
函数中通过Base
指针调用doSomething
函数时,会根据对象实际的vptr找到对应的虚函数表(如果是Sub1
对象,就是Sub1
的虚函数表;如果是Sub2
对象,就是Sub2
的虚函数表),然后调用相应的doSomething
函数。