跳转至

C++ OOP 面试高频知识点 - 08

多态:静态多态(重载)、动态多态(虚函数)

1. 多态的基本概念

多态(Polymorphism) 是面向对象编程的核心原则之一,它允许我们使用统一的接口处理不同类型的对象。C++ 提供了两种多态形式:静态多态(编译时多态)和 动态多态(运行时多态)。

class Shape {
public:
    virtual double area() const = 0;
};

class Rectangle : public Shape {
public:
    Rectangle(double w, double h) : width(w), height(h) {}

    double area() const override {
        return width * height;
    }

private:
    double width, height;
};

class Circle : public Shape {
public:
    Circle(double r) : radius(r) {}

    double area() const override {
        return 3.14159 * radius * radius;
    }

private:
    double radius;
};

void printArea(const Shape& shape) {
    cout << "Area: " << shape.area() << endl;
}

int main() {
    Rectangle rect(5, 10);
    Circle circle(5);

    printArea(rect);  // 调用 Rectangle::area()
    printArea(circle); // 调用 Circle::area()

    return 0;
}

2. 静态多态(编译时多态)

静态多态是在编译阶段确定调用的函数,主要通过以下方式实现:

2.1 函数重载(Function Overload)

函数重载是指在同一个作用域内,函数名称相同但参数列表不同。

void print(int x) {
    cout << "Integer: " << x << endl;
}

void print(double x) {
    cout << "Double: " << x << endl;
}

void print(const string& s) {
    cout << "String: " << s << endl;
}

int main() {
    print(10);        // 调用 print(int)
    print(3.14);      // 调用 print(double)
    print("Hello");   // 调用 print(const string&)
    return 0;
}

2.2 模板(Templates)

模板是 C++ 的泛型编程工具,可以根据类型自动生成函数或类。

template <typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    int x = add(1, 2);         // 自动生成 int 版本
    double y = add(1.5, 2.5);  // 自动生成 double 版本

    cout << "x = " << x << endl;
    cout << "y = " << y << endl;

    return 0;
}

3. 动态多态(运行时多态)

动态多态是在运行阶段确定调用的函数,主要通过虚函数实现。

3.1 虚函数(Virtual Functions)

虚函数是在基类中声明为 virtual 的成员函数。当在子类中重新实现虚函数时,会发生多态行为。

class Animal {
public:
    virtual void makeSound() {
        cout << "Animal makes a sound" << endl;
    }

    virtual ~Animal() {} // 虚析构函数
};

class Dog : public Animal {
public:
    void makeSound() override {
        cout << "Dog barks" << endl;
    }
};

class Cat : public Animal {
public:
    void makeSound() override {
        cout << "Cat meows" << endl;
    }
};

int main() {
    Animal* animals[] = {new Dog(), new Cat()};

    for (int i = 0; i < 2; ++i) {
        animals[i]->makeSound(); // 运行时确定调用的函数
    }

    for (int i = 0; i < 2; ++i) {
        delete animals[i];
    }

    return 0;
}

3.2 虚函数的实现机制

C++ 通过以下机制实现虚函数:

  1. 虚函数表(Virtual Table):每个包含虚函数的类都有一个虚函数表,存储该类的所有虚函数地址
  2. 虚指针(Virtual Pointer):每个对象都有一个虚指针,指向该类的虚函数表
  3. 动态绑定:当调用虚函数时,通过虚指针找到虚函数表,然后根据偏移量调用相应的函数

4. 静态多态与动态多态的比较

特性 静态多态 动态多态
确定时间 编译时 运行时
实现方式 函数重载、模板 虚函数
性能 较高(编译时绑定) 较低(运行时绑定)
灵活性 较低(需要明确类型) 较高(支持继承和多态)
代码复用 模板提供泛型编程 继承提供代码复用

5. 抽象类和接口

抽象类是包含至少一个纯虚函数的类。抽象类不能直接实例化,但可以作为基类。

class Shape {
public:
    virtual double area() const = 0; // 纯虚函数
};

class Rectangle : public Shape {
public:
    double area() const override {
        return width * height;
    }

private:
    double width, height;
};

// Shape s; // 错误:抽象类不能实例化

6. 常见问题和回答

问题 1:静态多态和动态多态的区别?

  • 静态多态:编译时确定调用的函数,通过重载和模板实现
  • 动态多态:运行时确定调用的函数,通过虚函数实现

问题 2:为什么需要虚析构函数?

如果类中有虚函数,析构函数应该是虚函数,否则在通过基类指针删除子类对象时会导致内存泄漏。

class Base {
public:
    virtual void foo() = 0;
    ~Base() { cout << "Base destructor" << endl; }
};

class Derived : public Base {
public:
    Derived() { data = new int[100]; }
    ~Derived() { 
        delete[] data; 
        cout << "Derived destructor" << endl; 
    }
    void foo() override {}

private:
    int* data;
};

int main() {
    Base* ptr = new Derived();
    delete ptr; // 内存泄漏!
    return 0;
}

问题 3:虚函数可以是模板函数吗?

不可以,虚函数不能是模板函数,因为模板参数在编译时确定,而虚函数在运行时确定。

class Base {
public:
    template <typename T>
    virtual void foo(T t) { // 错误:虚函数不能是模板函数
        cout << t << endl;
    }
};

7. 最佳实践

  1. 明确意图:根据需求选择合适的多态形式
  2. 设计清晰的接口:基类应该提供清晰的接口
  3. 使用虚析构函数:包含虚函数的类应该有虚析构函数
  4. 避免过度继承:继承层次应保持简单
  5. 使用抽象类:通过抽象类定义接口

总结

多态是 C++ 面向对象编程的核心概念之一,分为静态多态和动态多态两种形式。静态多态在编译时确定函数调用,提供较高的性能;动态多态在运行时确定函数调用,提供较高的灵活性。虚函数是实现动态多态的主要方式,而模板和函数重载是实现静态多态的常用方法。


练习建议: 1. 设计一个图形系统,支持多种形状的面积计算 2. 实现动态多态,通过基类指针调用不同子类的方法 3. 测试虚析构函数的重要性 4. 比较静态多态和动态多态的性能