【C++】 面向对象编程的三大特性之一:多态

多态

1. 多态的概念

多态是面向对象编程中的一个重要概念,它分为两种主要类型:静态多态性(编译时多态性)和动态多态性(运行时多态性)

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

2.1 函数重载

静态多态性的一种体现是函数重载。 函数重载允许在同一个作用域中声明多个同名函数,它们的参数类型或个数不同。在编译时,根据函数名和参数信息,编译器会选择正确的函数实现。

示例:

// 静态多态性的例子:函数重载
void print(int value) {
    // ...
}

void print(double value) {
    // ...
}

2.2 运算符重载

运算符重载也是静态多态性的一种表现。通过为类定义特定的运算符重载函数,可以在编译时实现对用户自定义类型的运算符操作。

示例:

#include <iostream>

class Complex {
private:
    double real;
    double imag;

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

    // 重载加法运算符
    Complex operator+(const Complex& other) const {
        return Complex(real + other.real, imag + other.imag);
    }

    // 打印复数
    void display() const {
        std::cout << real << " + " << imag << "i" << std::endl;
    }
};

int main() {
    Complex a(1.0, 2.0);
    Complex b(3.0, 4.0);

    // 使用重载的加法运算符
    Complex result = a + b;

    // 打印结果
    result.display();

    return 0;
}

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

动态多态性通过虚函数和继承来实现。在运行时,程序能够根据对象的实际类型来调用相应的函数,这为构建灵活的程序提供了基础。

3.1 虚函数与继承

示例:

class Shape {
public:
	//虚函数 virtual关键字
	virtual void draw() const {
		std::cout << "Drawing a shape." << std::endl;
	}
};

class Rectangle : public Shape {
public:
	// override 用于显式地标记在派生类中重写(覆盖)基类的虚函数。
	// 在使用override关键字时,编译器会检查是否存在基类中的对应虚函数,如果不存在,则会产生编译错误,这样可以帮助开发者避免潜在的错误。
	void draw() const override {
		std::cout << "Drawing a rectangle." << std::endl;
	}

	void specialFunction() const {
		std::cout << "Executing special function for rectangle." << std::endl;
	}
};

// 接收基类对象的函数
void drawShape(const Shape& shape) {
	shape.draw();
}

// 返回基类对象的函数
Shape getShape(bool isRectangle) {
	if (isRectangle) {
		return Rectangle();
	}
	else {
		return Shape();
	}
}

void Test08() {
	// 使用派生类对象调用接收基类对象的函数
	Rectangle rectangle;
	drawShape(rectangle);

	// 使用派生类对象作为返回值
	Shape shape = getShape(true);
	shape.draw(); 
}

输出结果:

Drawing a rectangle.
Drawing a shape.

第一行结果分析:

派生类Rectangle的对象可以传递给接收基类对象的函数drawShape,并且在该函数中,调用了派生类的重写函数draw。即父类指针或引用指向子类对象时,会调用子类重载父类的虚函数。从而出现运行时的多态性
具体实现:const Shape& shape = rectangle; shape.draw();

第二行结果分析:

C++中当派生类重写(override)了基类的虚函数(virtual function),通过基类指针或引用调用该虚函数时,会根据指针或引用指向的实际对象类型来决定调用哪个函数。

getShape(true)函数会触发以下操作:
(1)创建一个Rectangle类型的临时对象
(2)由于返回类型是Shape,会执行派生类向基类的隐式类型转换

所以该函数会返回一个Shape对象,而不是Rectangle对象。虽然Rectangle类重写了Shape类的draw函数,但是由于对象切片的问题,返回的对象类型被限定为Shape,因此调用shape.draw()时会执行Shape类的draw函数。

小结:

在上述例子中,派生类Rectangle的对象可以传递给接收基类对象的函数drawShape,并且在该函数中,调用了派生类的重写(override)函数draw。同时,我们通过getShape函数返回了一个基类对象,但是根据传入的参数,返回一个派生类对象Rectangle。 这样,我们可以在使用基类对象的地方实际上使用了派生类对象的功能,而不需要直接关心派生类的具体实现
这体现了面向对象编程中的多态性和封装性

3.2 虚函数表(vtable)

动态多态性的实现依赖于虚函数表(vtable)的机制。每个对象都有一个指向虚函数表的指针,表中存储了类的虚函数地址。在运行时,通过这个指针来查找并调用相应的虚函数。

根据上面的例子,多态实现从底层来看:

Shape 对象内存储着虚函数指针,指针指向它的虚函数表,表中存储着虚函数draw()的地址。而子类Rectangle 继承Shape时,也会继承这个父类(Shape)的虚函数表。当子类重写父类的虚函数时,会修改继承父类的虚函数表,修改为子类实现的虚函数。最后当父类指针或者引用指向子类的对象时,调用的虚函数就是子类实现的虚函数,从而实现运行时的多态性。

4. 多态的优点

  1. 灵活性和可扩展性: 多态使得程序能够适应不同类型的对象,增加了代码的灵活性和可扩展性。

  2. 简化代码: 多态能够通过相同的接口处理不同类型的对象,简化了代码结构,提高了可读性。

  3. 降低耦合度: 通过多态,代码之间的耦合度降低了,子类可以独立地进行修改和扩展,不会影响其他部分的代码。

5. 总结:

总体而言,多态是面向对象编程的核心思想之一,它使得程序更易于理解、维护和扩展。通过不同形式的多态性,程序员可以更灵活地处理各种复杂的情况。


希望各位多多支持,码字不易,thank you!
欢迎关注🔎点赞👍收藏⭐️留言📝

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值