c++多态


前言

多态是面向对象编程的三大特性之一(封装、继承、多态),它允许使用统一的接口来处理不同类型的对象。在C++中,多态主要通过虚函数和继承机制实现。

1. 多态的基本概念

多态分为两种类型:

  • 编译时多态(静态多态):通过函数重载和运算符重载实现

编译时多态是指在编译阶段就能确定具体调用哪个函数实现的多态形式,也称为静态多态或早期绑定。

  • 运行时多态(动态多态):通过虚函数和继承实现

运行时多态是指在程序运行时才能确定具体调用哪个函数实现的多态形式,也称为动态多态或晚期绑定。

可以去看看静态联编和动态联编与多态的关系

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

2.1 函数重载

#include 
using namespace std;

class Print {
public:
    void show(int i) {
        cout << "整数: " << i << endl;
    }
    
    void show(double f) {
        cout << "浮点数: " << f << endl;
    }
    
    void show(string s) {
        cout << "字符串: " << s << endl;
    }
};

int main() {
    Print obj;
    obj.show(5);
    obj.show(3.14);
    obj.show("Hello");
    return 0;
}

2.2 运算符重载

#include 
using namespace std;

class Complex {
private:
    double real, imag;
public:
    Complex(double r = 0, double i = 0) : real(r), imag(i) {}
    
    Complex operator + (const Complex& obj) {
        Complex temp;
        temp.real = real + obj.real;
        temp.imag = imag + obj.imag;
        return temp;
    }
    
    void display() {
        cout << real << " + " << imag << "i" << endl;
    }
};

int main() {
    Complex c1(3, 4), c2(5, 6);
    Complex c3 = c1 + c2;
    c3.display();  // 输出: 8 + 10i
    return 0;
}

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

3.1 虚函数

虚函数是实现运行时多态的关键。通过在基类中使用virtual关键字声明函数,派生类可以重写这些函数。

#include 
using namespace std;

class Base {
public:
    virtual void show() {
        cout << "Base class show()" << endl;
    }
    
    void print() {
        cout << "Base class print()" << endl;
    }
};

class Derived : public Base {
public:
    void show() override {  // override关键字(C++11)表示重写虚函数
        cout << "Derived class show()" << endl;
    }
    
    void print() {
        cout << "Derived class print()" << endl;
    }
};

int main() {
    Base* bptr;
    Derived d;
    bptr = &d;
    
    // 运行时多态,调用Derived类的show()
    bptr->show();  // 输出: Dericed class show()
    
    // 非虚函数,编译时绑定,调用Base类的print()
    bptr->print(); // 输出: Base class print()
    
    return 0;
}

3.2 纯虚函数和抽象类

包含纯虚函数的类称为抽象类,不能实例化。

#include 
using namespace std;

class Shape {  // 抽象类
public:
    virtual float area() = 0;  // 纯虚函数
    virtual float perimeter() = 0;
};

class Rectangle : public Shape {
private:
    float length, width;
public:
    Rectangle(float l, float w) : length(l), width(w) {}
    
    float area() override {
        return length * width;
    }
    
    float perimeter() override {
        return 2 * (length + width);
    }
};

class Circle : public Shape {
private:
    float radius;
public:
    Circle(float r) : radius(r) {}
    
    float area() override {
        return 3.14159 * radius * radius;
    }
    
    float perimeter() override {
        return 2 * 3.14159 * radius;
    }
};

int main() {
    Shape* shapes[2];
    shapes[0] = new Rectangle(5, 4);
    shapes[1] = new Circle(3);
    
    for (int i = 0; i < 2; i++) {
        cout << "Area: " << shapes[i]->area() << endl;
        cout << "Perimeter: " << shapes[i]->perimeter() << endl;
    }
    
    delete shapes[0];
    delete shapes[1];
    return 0;
}
  • 用作接口:定义派生类必须实现的接口规范

  • 可以包含普通成员:可以有数据成员和普通成员函数

  • 可以有实现:纯虚函数可以在类外提供实现(但仍需派生类重写)

纯虚函数和抽象类都是用基类指针指向派生类

4. 虚析构函数

当基类指针指向派生类对象时,如果基类析构函数不是虚函数,则只会调用基类析构函数,可能导致内存泄漏。

#include 
using namespace std;

class Base {
public:
    Base() { cout << "Base constructor" << endl; }
    virtual ~Base() { cout << "Base destructor" << endl; }  // 虚析构函数
};

class Derived : public Base {
public:
    Derived() { cout << "Derived constructor" << endl; }
    ~Derived() { cout << "Derived destructor" << endl; }
};

int main() {
    Base* b = new Derived();
    delete b;  // 会调用Derived和Base的析构函数
    return 0;
}

所以如果将基类的析构函数置为虚析构就可以减少内存泄漏的情况

 override和final关键字(C++11)

  • override:显式指明函数重写基类虚函数

  • final:禁止派生类重写虚函数或禁止类被继承

class Base {
public:
    virtual void foo() {}
    virtual void bar() final {}  // 不能被子类重写
};

class Derived : public Base {
public:
    void foo() override {}  // 正确: 重写基类虚函数
    // void bar() {}  // 错误: bar是final的
};

class FinalClass final {};  // 不能被继承
// class TryInherit : public FinalClass {};  // 错误

总结

C++中的多态是面向对象编程的核心特性,它允许通过统一的接口操作不同类型的对象,显著提高了代码的灵活性和可扩展性。多态主要分为编译时多态和运行时多态两种形式:编译时多态通过函数重载、模板和运算符重载实现,在编译阶段即可确定具体调用,执行效率高但灵活性较低;运行时多态则通过虚函数机制实现,借助虚函数表(vtable)在程序运行时动态绑定函数调用,虽然引入了一定的性能开销,但能够实现真正的动态行为绑定。

你可能感兴趣的:(c++,面试,开发语言)