MST

星途 面试题库

面试题:C++中虚函数与普通成员函数在多态实现上的区别

请阐述在C++中,虚函数和普通成员函数在实现多态性方面有何不同?通过代码示例说明如何利用虚函数实现运行时多态,以及普通成员函数为何无法实现同样效果。
29.2万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

虚函数与普通成员函数在多态性方面的不同

  1. 虚函数
    • 实现多态方式:通过在基类中声明函数为虚函数(使用 virtual 关键字),派生类可以重写(override)该虚函数。当通过基类指针或引用调用虚函数时,会根据指针或引用实际指向的对象类型来决定调用哪个类的虚函数版本,从而实现运行时多态。
    • 动态绑定:运行时根据对象的实际类型决定调用哪个函数版本,体现了动态多态性。
  2. 普通成员函数
    • 实现多态方式:普通成员函数调用是在编译时根据指针或引用的静态类型决定的,不具备运行时根据对象实际类型来选择函数版本的能力。
    • 静态绑定:编译时就确定了调用哪个类的函数版本,属于静态多态(函数重载也属于静态多态,但这里主要对比与虚函数运行时多态的区别)。

代码示例利用虚函数实现运行时多态

#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 函数被声明为虚函数。DogCat 类继承自 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 函数是普通成员函数。虽然 CircleRectangle 类也有 draw 函数,但由于 draw 不是虚函数,通过 Shape 指针调用 draw 函数时,调用的是 Shape 类的 draw 函数版本,而不是根据对象实际类型调用 CircleRectangle 类的 draw 函数,无法实现运行时多态。