【C++】多态

本篇是自己阅读加上自己对“多态”的理解,若有不足之处,感谢指出~

多态

多态最常见的用法就是声明基类类型的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。如果没有使用虚函数的话,即没有利用C++多态性,则利用基类指针调用相应的函数的时候,将总被限制在基类函数本身,而无法调用到子类中被重写过的函数。因为没有多态性,函数调用的地址将是固定的,因此将始终调用到同一个函数,这就无法实现“一个接口,多种方法”的目的了。

在C++ Primer有关于OOP编程的描述是这样的。

OOP不仅仅是将数据和方法合并为类定义;还有助于创建可重用的代码,这将减少大量的工作(继承、类的复用)。

  • 封装(信息隐藏)可以保护数据,使其免遭不适当的访问(使得代码模块化);
  • 多态让您能够为运算符和函数创建多个定义,通过编程上下文来确定使用哪个定义;
    • 编译时多态:通过重载函数实现
    • 运行时多态性:通过虚函数实现
  • 继承让您能够使用旧类派生出新类(扩展已存在的代码)。

这些都是面向对象(OOP)所指的特性。还包括:

  • 抽象
  • 代码的可重用性

在C++面试中很有可能会问你C++的三个特性:封装、继承、多态

有关于这三点特性,从设计模式中会受益许多,一个好的建议就是去学习设计模式。推荐《Easy搞定设计模式》这本PDF,网上可以搜到。


关于多态,C++ primer给的定义包括多个方面:

  1. 函数重载

函数多态是C++在C语言的基础上新增的功能,默认参数让您能够使用不同数目的参数调用同一个函数,而函数多态(函数重载)让您能够使用多个同名的函数。术语“多态”指的是拥有多种形式,因此函数多态允许函数可以有多种形式。类似地,术语“函数重载”指的是可以有多个同名的含糊,因此对名称进行了重载。

  1. 类继承:有些继承关系是多态的,这意味着相同的方法名称可能导致依赖于对象类型的行为。(如下代码所示)
  2. 运算符重载

class Fruit {
public:
	virtual void getName() {
		cout << "一种水果" << endl;;
	}
	void getColor() {
		cout << "水果的颜色" << endl;
	}

};
/*
	还可以声明其他的类和添加您所需要的方法以满足业务需求
	您可以尝试创建一个Pear类来更加了解多态行为,更多的可以去了解纯虚函数、抽象等
*/
class Apple : public Fruit {
public:
	virtual void getName() {
		cout << "我是苹果" << endl;
	}
	virtual void getColor() {
		cout << "红色苹果" << endl;;
	}
};
int main()
{
	//声明父类和子类的对象
	Fruit fruit;
	Apple apple;
	//声明一个指向父类的父类指针
	Fruit *anotherFruit = &fruit;
	anotherFruit->getName();
	anotherFruit->getColor();
	//令父类指针指向子类对象
	anotherFruit = &apple;
	anotherFruit->getName(); //由于fetName()是虚函数,因此调用时指向虚函数表中该函数所在的位置
    /*
    	有virtual才能发生多态现象,没有virtual就按类型调用。
    	而getColor()不是虚函数,因此调用基类的getColor()
    */
	anotherFruit->getColor(); 
	system("pause");
	return 0;
}

输出如下:

再谈“接口”

不同对象调用使用相同方法实现不同操作,也即,方法完成的行为取决于调用该方法的对象。说着有点拗口,我自己理解就是类层面的“重载”。怎么去理解?代码!还是刚才的两个类,额外添加一个Pear类。

//先修改基类,使其变为抽象类
// 1. 抽象类不用定义,只需声明即可
// 2. 抽象类方法前必须有virtual声明
// 3. 抽象类不能实例化对象,但是可以创建对象指针
 /*
	定义一个水果类抽象基类。用于定操作和规定函数,提供方法
*/
class Fruit {
public:
	virtual void getName() = 0;
	virtual void getColor() = 0;
};

但凡是纯虚函数,子类继承必须全部重定义!

// 定义苹果类和犁类
class Apple : public Fruit {
public:
	virtual void getName() {
		cout << "我是苹果" << endl;
	}
	virtual void getColor() {
		cout << "红色苹果" << endl;;
	}
};
class Pear : public Fruit {
public:
	virtual void getName() {
		cout << "我是犁" << endl;
	}
	virtual void getColor() {
		cout << "黄犁" << endl;;
	}
};

创建指针对象指向不同的子类,实现不同的操作。

int main() {
    // 通过创建基类的指针对象可以实现多台,就不用访问具体的类,只需要根据基类知道其中的操作即可
    Fruit *apple = new Apple;
	Fruit *pear = new Pear;
	apple->getName();
	apple->getColor();
	pear->getName();
	pear->getColor();
	return 0;
}

输出如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欧恩意

如有帮助,感谢打赏!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值