面试题答案
一键面试虚函数与普通成员函数在多态性方面的不同
- 虚函数:
- 实现多态方式:通过在基类中声明函数为虚函数(使用
virtual
关键字),派生类可以重写(override)该虚函数。当通过基类指针或引用调用虚函数时,会根据指针或引用实际指向的对象类型来决定调用哪个类的虚函数版本,从而实现运行时多态。 - 动态绑定:运行时根据对象的实际类型决定调用哪个函数版本,体现了动态多态性。
- 实现多态方式:通过在基类中声明函数为虚函数(使用
- 普通成员函数:
- 实现多态方式:普通成员函数调用是在编译时根据指针或引用的静态类型决定的,不具备运行时根据对象实际类型来选择函数版本的能力。
- 静态绑定:编译时就确定了调用哪个类的函数版本,属于静态多态(函数重载也属于静态多态,但这里主要对比与虚函数运行时多态的区别)。
代码示例利用虚函数实现运行时多态
#include <iostream>
class Animal {
public:
virtual void speak() {
std::cout << "Animal makes a sound" << std::endl;
}
};
class Dog : public Animal {
public:
void speak() override {
std::cout << "Dog barks" << std::endl;
}
};
class Cat : public Animal {
public:
void speak() override {
std::cout << "Cat meows" << std::endl;
}
};
int main() {
Animal* animal1 = new Dog();
Animal* animal2 = new Cat();
animal1->speak();
animal2->speak();
delete animal1;
delete animal2;
return 0;
}
在上述代码中,Animal
类的 speak
函数被声明为虚函数。Dog
和 Cat
类继承自 Animal
并重写了 speak
函数。在 main
函数中,通过 Animal
指针指向不同的派生类对象,调用 speak
函数时,实际调用的是对应派生类重写后的版本,实现了运行时多态。
普通成员函数无法实现同样效果的代码示例
#include <iostream>
class Shape {
public:
void draw() {
std::cout << "Drawing a shape" << std::endl;
}
};
class Circle : public Shape {
public:
void draw() {
std::cout << "Drawing a circle" << std::endl;
}
};
class Rectangle : public Shape {
public:
void draw() {
std::cout << "Drawing a rectangle" << std::endl;
}
};
int main() {
Shape* shape1 = new Circle();
Shape* shape2 = new Rectangle();
shape1->draw();
shape2->draw();
delete shape1;
delete shape2;
return 0;
}
在这段代码中,Shape
类的 draw
函数是普通成员函数。虽然 Circle
和 Rectangle
类也有 draw
函数,但由于 draw
不是虚函数,通过 Shape
指针调用 draw
函数时,调用的是 Shape
类的 draw
函数版本,而不是根据对象实际类型调用 Circle
或 Rectangle
类的 draw
函数,无法实现运行时多态。