多态性对程序结构的影响
- 编译时:
- 在编译阶段,编译器根据指针或引用的静态类型(即声明时的类型)来确定可调用的函数集合。例如,有一个基类
Base
和派生类Derived
,若有Base* ptr;
,编译器会查找Base
类中定义的函数(包括虚函数),对于虚函数,编译器会为其生成虚函数表指针(vptr)相关的信息,用于运行时动态绑定。
- 示例代码如下:
#include <iostream>
class Base {
public:
virtual void print() {
std::cout << "Base::print()" << std::endl;
}
};
class Derived : public Base {
public:
void print() override {
std::cout << "Derived::print()" << std::endl;
}
};
- 在编译这段代码时,编译器会为
Base
类生成虚函数表,其中包含print
函数的地址,Derived
类也会有自己的虚函数表,并且会覆盖Base
类虚函数表中print
函数的地址为Derived::print
的地址。
- 运行时:
- 在运行时,程序根据指针或引用所指向对象的实际类型(动态类型)来决定调用哪个虚函数的实现。这就是动态绑定。
- 继续上面的示例,当执行以下代码时:
int main() {
Base* basePtr = new Derived();
basePtr->print();
delete basePtr;
return 0;
}
- 在运行
basePtr->print();
时,程序会根据basePtr
所指向的实际对象(Derived
类型的对象),通过虚函数表找到Derived::print
函数并调用,输出Derived::print()
。这体现了多态性使得程序在运行时能够根据对象的实际类型做出不同的行为,从而增强了程序的灵活性和可扩展性。例如在大型软件系统中,如果有一个处理图形的类继承体系,基类Shape
有虚函数draw
,不同的派生类Circle
、Rectangle
等重写draw
函数,通过基类指针或引用就可以在运行时根据实际的图形对象类型调用相应的draw
函数,而不需要在编译时就确定具体的图形类型,使得代码结构更加清晰,易于维护和扩展新的图形类型。