多态性(Polymorphism)是面向对象编程的一个核心概念,它允许相同的操作作用于不同的对象上,并且可以根据对象的实际类型执行不同的操作。多态性有两种主要形式:静态多态性和动态多态性。

一、多态性

多态性(Polymorphism)指的是相同的接口可以对应不同的实现,使同一操作能够作用于不同的对象并表现出不同的行为。

二、静态多态性

静态多态性(Static Polymorphism),也称为编译时多态性,是在编译时决定调用哪个方法。常见的实现方式包括方法重载运算符重载

1. 方法重载

方法重载(Function Overloading)是指在同一个类中,多个函数的名字相同,但参数列表不同(参数的数量或类型不同)。编译器根据函数调用时传递的参数来决定调用哪个具体函数。

#include <iostream>

class MathOperations {
public:
    int add(int a, int b) {
        return a + b;
    }

    double add(double a, double b) {
        return a + b;
    }

    int add(int a, int b, int c) {
        return a + b + c;
    }
};

int main() {
    MathOperations math;
    std::cout << math.add(5, 3) << std::endl;        // 调用第一个 add 方法
    std::cout << math.add(2.5, 3.5) << std::endl;    // 调用第二个 add 方法
    std::cout << math.add(1, 2, 3) << std::endl;     // 调用第三个 add 方法
    return 0;
}

2. 运算符重载

运算符重载(Operator Overloading)是指允许开发者定义或改变运算符的行为。在C++中,可以重载大多数运算符。

#include <iostream>

class Complex {
public:
    double real, imag;

    Complex(double r, double i) : real(r), imag(i) {}

    Complex operator+(const Complex& other) {
        return Complex(real + other.real, imag + other.imag);
    }

    void display() {
        std::cout << real << " + " << imag << "i" << std::endl;
    }
};

int main() {
    Complex c1(1.0, 2.0), c2(2.0, 3.0);
    Complex c3 = c1 + c2;
    c3.display(); // 输出 "3.0 + 5.0i"
    return 0;
}

三、动态多态性

动态多态性(Dynamic Polymorphism),也称为运行时多态性,是在运行时决定调用哪个方法。常见的实现方式包括虚函数纯虚函数

1. 虚函数

虚函数(Virtual Functions)允许子类重写父类的方法。在运行时,调用的具体方法取决于对象的实际类型。

#include <iostream>

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

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

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

int main() {
    Animal* myDog = new Dog();
    Animal* myCat = new Cat();

    myDog->makeSound(); // 输出 "Dog barks"
    myCat->makeSound(); // 输出 "Cat meows"

    delete myDog;
    delete myCat;
    return 0;
}

2. 纯虚函数

接口实现(通过抽象类)
C++没有直接的接口,但可以通过纯虚函数(pure virtual function)和抽象类来实现接口的效果。

#include <iostream>

class Drawable {
public:
    virtual void draw() = 0; // 纯虚函数
};

class Circle : public Drawable {
public:
    void draw() override {
        std::cout << "Drawing Circle" << std::endl;
    }
};

class Rectangle : public Drawable {
public:
    void draw() override {
        std::cout << "Drawing Rectangle" << std::endl;
    }
};

int main() {
    Drawable* shapes[] = {new Circle(), new Rectangle()};

    for (Drawable* shape : shapes) {
        shape->draw(); // 根据实际对象类型调用相应的 draw 方法
    }

    // 释放内存
    for (Drawable* shape : shapes) {
        delete shape;
    }

    return 0;
}

四、静态多态性 vs 动态多态性
在这里插入图片描述

总结
多态性是面向对象编程的重要特性,通过静态多态性和动态多态性实现对象的多样性和灵活性。静态多态性在编译时决定方法的选择,主要通过方法重载和运算符重载实现,而动态多态性在运行时决定方法的选择,主要通过虚函数和抽象类实现。理解并灵活运用这两种多态性,对于编写高效、可维护和可扩展的代码至关重要。

抽象类

抽象类是面向对象编程中的一个概念,它是一种不能被实例化的类,专门用来定义子类的通用接口和行为。抽象类包含至少一个纯虚函数(pure virtual function),也可以包含其他普通成员函数和数据成员。抽象类的主要目的是为子类提供一个通用的框架,强制子类实现某些特定的函数,从而实现多态性。

抽象类的特点
不能实例化:抽象类不能创建对象,只能被继承。
包含纯虚函数:纯虚函数是没有具体实现的函数,必须在派生类中实现。
可以包含普通成员:抽象类可以包含数据成员和已经实现的普通成员函数。
用于定义接口:抽象类提供一个框架,强制子类实现特定的功能。

纯虚函数
纯虚函数是一个在基类中声明但没有定义的函数。它的声明形式如下:

virtual void functionName() = 0;
//= 0表示该函数是纯虚函数,必须在派生类中实现。

以下是一个包含纯虚函数的抽象类的示例:

#include <iostream>

// 抽象类
class Animal {
public:
    // 纯虚函数
    virtual void makeSound() = 0;

    // 普通成员函数
    void sleep() {
        std::cout << "Animal is sleeping" << std::endl;
    }
};

// 派生类
class Dog : public Animal {
public:
    void makeSound() override {
        std::cout << "Dog barks" << std::endl;
    }
};

// 派生类
class Cat : public Animal {
public:
    void makeSound() override {
        std::cout << "Cat meows" << std::endl;
    }
};

int main() {
    // Animal a; // 错误!不能实例化抽象类

    Dog myDog;
    Cat myCat;

    myDog.makeSound(); // 输出 "Dog barks"
    myDog.sleep();     // 输出 "Animal is sleeping"

    myCat.makeSound(); // 输出 "Cat meows"
    myCat.sleep();     // 输出 "Animal is sleeping"

    // 使用基类指针实现多态
    Animal* animals[] = {&myDog, &myCat};
    for (Animal* animal : animals) {
        animal->makeSound(); // 输出 "Dog barks" 和 "Cat meows"
    }

    return 0;
}

解释
抽象类 Animal:
包含一个纯虚函数 makeSound,表示所有派生类都必须实现这个函数。
包含一个普通成员函数 sleep,可以在派生类中直接使用。

派生类 Dog 和 Cat:
都继承了 Animal 并实现了纯虚函数 makeSound。

多态性:
在 main 函数中,使用基类指针数组 animals 指向不同的派生类对象,并调用它们的 makeSound 方法。程序会根据实际对象类型调用相应的实现。

总结
抽象类是定义一组通用接口和行为的类,包含至少一个纯虚函数,不能被实例化。它们为派生类提供了一个框架,强制派生类实现特定的功能,从而实现多态性。通过使用抽象类,可以编写更加灵活和可扩展的代码。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐