面试题答案
一键面试虚拟函数与普通成员函数实现多态机制的不同
- 虚拟函数:
- 机制:C++通过虚函数表(vtable)和虚指针(vptr)来实现多态。当一个类中定义了虚函数,编译器会为该类生成一个虚函数表,其中存放了虚函数的地址。每个包含虚函数的类的对象都有一个虚指针,它指向该类的虚函数表。在运行时,根据对象的实际类型,通过虚指针找到对应的虚函数表,进而调用合适的虚函数版本,实现动态绑定,即多态。
- 特点:动态绑定,根据对象的实际类型在运行时决定调用哪个函数版本,提高了程序的灵活性。
- 普通成员函数:
- 机制:普通成员函数在编译时就确定了调用关系,即静态绑定。编译器根据对象的声明类型来确定调用哪个函数版本。
- 特点:静态绑定,效率相对较高,但缺乏灵活性,不能根据对象的实际类型来动态选择函数版本。
代码示例
#include <iostream>
class Animal {
public:
// 虚函数
virtual void speak() {
std::cout << "Animal speaks" << 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;
}
};
void makeSound(Animal& animal) {
// 这里会根据animal的实际类型调用相应的speak函数,体现多态
animal.speak();
}
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;
}
};
void drawShape(Shape& shape) {
// 这里根据shape的声明类型调用draw函数,不会体现多态
shape.draw();
}
int main() {
Animal animal;
Dog dog;
Cat cat;
makeSound(animal);
makeSound(dog);
makeSound(cat);
Shape shape;
Circle circle;
Rectangle rectangle;
drawShape(shape);
drawShape(circle);
drawShape(rectangle);
return 0;
}
在上述代码中,Animal
类的speak
函数是虚函数,Dog
和Cat
类重写了speak
函数。在makeSound
函数中,通过Animal&
引用调用speak
函数,根据传入对象的实际类型(Dog
或Cat
)来动态调用相应的speak
版本,体现了多态。而Shape
类的draw
函数是普通成员函数,Circle
和Rectangle
类也有自己的draw
函数,但在drawShape
函数中,根据Shape&
引用的声明类型,始终调用Shape
类的draw
函数,不会体现多态。