面试题答案
一键面试- 保障代码扩展性方面
- 开闭原则:通过将
draw
函数定义为虚函数,使得在添加新的图形类型(如Triangle
等新子类)时,无需修改已有代码(如Shape
基类及其他已存在的子类代码)。新的图形子类只需继承Shape
基类,并实现draw
虚函数即可。例如:
class Triangle : public Shape { public: void draw() override { // 绘制三角形的具体实现 } };
- 多态性:父类
Shape
的指针或引用可以指向不同子类的对象,在调用draw
函数时,根据实际对象的类型调用相应子类的draw
实现。这使得在使用图形绘制库时,代码可以统一处理各种图形,而不必为每种图形类型编写单独的处理逻辑。例如:
Shape* shape1 = new Circle(); Shape* shape2 = new Rectangle(); shape1->draw(); // 调用 Circle 的 draw 函数 shape2->draw(); // 调用 Rectangle 的 draw 函数
- 开闭原则:通过将
- 虚函数表和动态绑定机制的作用
- 虚函数表:每个包含虚函数的类(如
Shape
及其子类)都有一个虚函数表(vtable)。当创建一个对象时,对象的内存布局中会包含一个指向其所属类虚函数表的指针(vptr)。虚函数表中存储了类中虚函数的地址。对于Shape
基类,虚函数表中存储了Shape::draw
的地址。当子类(如Circle
)重写draw
函数时,子类的虚函数表中对应的draw
函数地址被替换为Circle::draw
的地址。这使得通过对象的 vptr 可以快速找到对应类的虚函数实现。 - 动态绑定机制:在运行时,当通过父类指针或引用调用虚函数(如
shape1->draw()
)时,程序会根据对象实际的类型(即对象 vptr 指向的虚函数表)来确定调用哪个版本的虚函数。这就是动态绑定。在添加新图形类型时,新子类会有自己的虚函数表,通过动态绑定机制,即使在编译时不知道具体对象类型(只知道是Shape
指针或引用),运行时也能正确调用新子类的draw
函数,从而支持了代码的扩展性。
- 虚函数表:每个包含虚函数的类(如