浅谈C++|多态篇

本文详细介绍了C++中的多态,包括静态多态(函数重载和运算符重载)、动态多态(通过虚函数实现),并探讨了抽象类、纯虚函数、虚析构的概念及其应用。通过实例展示了多态的优势和使用技巧,以及解决子类析构问题的方法。
摘要由CSDN通过智能技术生成


1.多态的基本概念

多态是C++面向对象三大特性之一多态分为两类
1. 静态多态:函数重载和运算符重载属于静态多态,复用函数名·

2.动态多态:派生类和虚函数实现运行时多态
静态多态和动态多态区别:
·静态多态的函数地址早绑定–编译阶段确定函数地址

·动态多态的函数地址晚绑定–运行阶段确定函数地址下面通过案例进行讲解多态

动态多态满足条件

1、有继承关系
2、子类重写父类的虚函数

动态多态使用
父类的指针或者引用执行子类对象

重写:函数返回值类型函数名参数列表完全—致称为重写

 静态多态代码:

#include <iostream>
using namespace std;
class dongwu {
public:
	void speak() {
		cout << "动物叫" << endl;
	}
};

class cat :public dongwu {
	void speak() {
		cout << "猫叫" << endl;
	}
};
//早绑定,编译阶段就确定函数的地址

void speak(dongwu& p) {
	p.speak();
}
void fun() {
	cat p;
	speak(p);
}
int main() {
	fun();
	cat p;
	//发生隐式转换,只能把儿子转为父亲,退化
	dongwu m = p;
	m.speak();
	return 0;
}

注意转化,以及早绑定的特性是执行当前的类型的函数,不执行儿子的函数

动态动态代码: 

#include <iostream>
using namespace std;
class dongwu {
public:
	//virtual虚函数关键字
	virtual void speak() {
		cout << "动物叫" << endl;
	}
};

class cat :public dongwu {
	//子类的virtual可加可不加
	virtual void speak() {
		cout << "猫叫" << endl;
	}
};

//晚绑定,执行子类的函数
void speak(dongwu& p) {
	p.speak();
}
void fun() {
	cat p;
	speak(p);
}
int main() {
	fun();
	
	return 0;
}

二.多态的底层原理

我们先看以下代码:

#include <iostream>
using namespace std;
class father1 {
public:
	void speak() {
		cout << "动物叫" << endl;
	}
};
class father2 {
public:
	virtual void speak() {
		cout << "动物叫" << endl;
	}
};
int main() {
	cout << sizeof(father1) << endl;
	cout << sizeof(father2) << endl;

	return 0;
}

 当类的成员函数加入虚函数关键字后,会发现类的大小发生了改变。此时类的内部结构。此时类的内部会多一个指针虚函数(表)指针,虚函数指针指向虚函数表,虚函数表中存储虚函数的入口地址

那么当派生类继承基类后,如果成员函数没有重名,那么会完全继承父类的结构。 

 

 但是当派生类,重写基函数的虚函数时,派生类中的虚函数表会发生改变,此时虚函数表指向派生类的虚函数,基类的虚函数被覆盖。

 

 此时,我们有派生类隐式转换为基类时,虚函数表中的内容并不改变,此时调用虚函数,执行的是派生类的虚函数。

三.多态的优点 

1、组织结构清晰

2、可读性强

3、对于前期和后期扩展以及维护性高

 普通计算机类:

#include <iostream>
using namespace std;
class jisuanqi {
public:
	int a, b;
	int jisuan(string fu) {
		if (fu == "+") {
			return a + b;
		}
		else if (fu == "-") {
			return a - b;
		}
		else if (fu == "*") {
			return a * b;
		}
	}
};
void fun() {
	jisuanqi q;
	q.a = 200;
	q.b = 100;
	cout << q.a << " - " << q.b << " = " << q.jisuan("-") << endl;
	cout << q.a << " + " << q.b << " = " << q.jisuan("+") << endl;
	cout << q.a << " * " << q.b << " = " << q.jisuan("*") << endl;

}
int main() {
	fun();
	return 0;
}

 多态计算机类:

#include <iostream>
using namespace std;
class jisuanqi {
public:
	int a;
	int b;
	virtual int jisuan() {
		return 0;
	}
};

class add :public jisuanqi {
	virtual int jisuan() {
		return a+b;
	}
};

class jian :public jisuanqi {
	virtual int jisuan() {
		return a - b;
	}
};

class cheng:public jisuanqi {
	virtual int jisuan() {
		return a * b;
	}
};

void fun() {
	jisuanqi* p = new add;
	p->a = 200;
	p->b = 100;
	cout << p->a << " + " << p->b << " = " << p->jisuan()<<endl;
	delete p;
	
	p = new jian;
	p->a = 200;
	p->b = 100;
	cout << p->a << " - " << p->b << " = " << p->jisuan()<<endl;
	delete p;


	p = new cheng;
	p->a = 200;
	p->b = 100;
	cout << p->a << " * " << p->b << " = " << p->jisuan()<<endl;
	delete p;
}
int main() {
	fun();
	return 0;
}

四.纯虚函数和抽象类

在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容因此可以将虚函数改为纯虚函数。当类中有了纯虚函数,这个类也称为抽象类

纯虚函数语法: virtual    返回值类型   函数名︰(参数列表)= 0 ;

抽象类特点:
    ·无法实例化对象
    ·子类必须重写抽象类中的纯虚函数,否则也属于抽象类
 

 代码:

#include <iostream>
using namespace std;

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


class son :public father{
public:
	void fun() {
		cout << "我是sond" << endl;
	}
};

void fun() {
	//多态f必须是指针或者引用
	//father f; 报错不可实例化
	father* f = new son;
	f->fun();
}
int main() {
	fun();
	return 0;
}

案例制作饮品:

#include <iostream>
using namespace std;
class father {
public:
	virtual void zhushui() = 0;
	virtual void chongpao() = 0;
	virtual void daoru() = 0;
	virtual void jialiao() = 0;
	void fun() {
		zhushui();
		chongpao();
		daoru();
		jialiao();
	}
};

class tea :public father{
	void zhushui() {
		cout << "煮山泉水" << endl;
	};
	void chongpao() {
		cout << "冲茶" << endl;
	};
	void daoru() {
		cout << "倒入茶杯中" << endl;
	};
	void jialiao() {
		cout << "加入枸杞" << endl;
	};
};

class kafei : public father{
	void zhushui() {
		cout << "煮水" << endl;
	};
	void chongpao() {
		cout << "冲咖啡" << endl;
	};
	void daoru() {
		cout << "倒入咖啡杯中" << endl;
	};
	void jialiao() {
		cout << "加入奶和糖" << endl;
	};
};
//函数接口
void fun(father* p) {
	p->fun();
	delete p;
}
int main() {
	fun(new tea);
	cout << "----------" << endl;
	fun(new kafei);
	return 0;
}

五. 虚析构和纯虚析构

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方式:

将父类中的析构函数改为虚析构或者纯虚析构


虚析构和纯虚析构共性:
·可以解决父类指针释放子类对象·都需要有具体的函数实现


虚析构和纯虚析构区别:
·如果是纯虚析构,该类属于抽象类,无法实例化对象

代码: 

#include <iostream>
using namespace std;
class father {
public:
	//纯虚函数
	virtual void fun() =0;
	father() {
		cout << "father构造函数" << endl;
	}
	~father() {
		cout << "father析构函数" << endl;
	}
};

class son :public father {
public:
	//堆区开辟数据
	son(int age) {
		cout << "son构造函数" << endl;
		this->age = new int(age);
	}

	~son() {
		cout << "son析构函数" << endl;
		if (this->age != NULL) {
			delete age;
			age = NULL;
		}
	}
	void fun() {
		cout << *age<< "son的fun函数调用" << endl;
	}
	int* age;
};
void fun() {
	
	father* p = new son(21);
	delete p;
}
int main() {
	fun();
	return 0;
}

如图,当发生多态时,基类并不会调用子类的析构函数,当子类中含有堆区开辟的空间时。会造成内存泄漏。此时需要虚析构或纯虚析构来解决。

虚析构代码: 

#include <iostream>
using namespace std;
class father {
public:
	//纯虚函数
	virtual void fun() =0;
	father() {
		cout << "father构造函数" << endl;
	}
	virtual ~father() {
		cout << "father析构函数" << endl;
	}
};

class son :public father {
public:
	//堆区开辟数据
	son(int age) {
		cout << "son构造函数" << endl;
		this->age = new int(age);
	}

	~son() {
		cout << "son析构函数" << endl;
		if (this->age != NULL) {
			delete age;
			age = NULL;
		}
	}
	void fun() {
		cout << *age<< "son的fun函数调用" << endl;
	}
	int* age;
};
void fun() {
	
	father* p = new son(21);
	delete p;
}
int main() {
	fun();
	return 0;
}

纯虚析构

#include <iostream>
using namespace std;
class father {
public:
	//纯虚函数
	virtual void fun() =0;
	father() {
		cout << "father构造函数" << endl;
	}
	virtual ~father() = 0;
};
//纯虚函数必须
father::~father()
{
	cout << "father析构函数" << endl;
}

class son :public father {
public:
	//堆区开辟数据
	son(int age) {
		cout << "son构造函数" << endl;
		this->age = new int(age);
	}

	~son() {
		cout << "son析构函数" << endl;
		if (this->age != NULL) {
			delete age;
			age = NULL;
		}
	}
	void fun() {
		cout << *age<< "son的fun函数调用" << endl;
	}
	int* age;
};
void fun() {
	
	father* p = new son(21);
	delete p;
}
int main() {
	fun();
	return 0;
}

案例计算机

#include <iostream>
using namespace std;

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

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

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


class CPU_intel : public CPU {
public:
	void func() {
		cout << "intel的CPU工作" << endl;
	}
};

class Graphics_card_intel : public Graphics_card {
public:
	void func() {
		cout << "intel的显卡工作" << endl;
	}
};



class Memory_Module_intel : public Memory_Module {
public:
	void func() {
		cout << "intel的内存条工作" << endl;
	}
};



class CPU_lenovo: public CPU {
public:
	void func() {
		cout << "联想的CPU工作" << endl;
	}
};

class Graphics_card_lenovo : public Graphics_card {
public:
	void func() {
		cout << "联想的显卡工作" << endl;
	}
};
class Memory_Module_lenovo : public Memory_Module {
public:
	void func() {
		cout << "联想的内存条工作" << endl;
	}
};
class computer {
public:
	//当传入的是子类时发生多态
	computer() {};
	computer(CPU* CPU , Memory_Module* m, Graphics_card* g) {
		this->cpu = CPU;
		this->m = m;
		this->g = g;
	}
	void work() {
		cpu->func();
		m->func();
		g->func();
	}
private:
	CPU* cpu;
	Memory_Module* m;
	Graphics_card* g;
};

void fun() {
	CPU_lenovo* c1 = new CPU_lenovo;
	CPU_intel* c2 = new CPU_intel;
	Graphics_card_intel* g1 = new Graphics_card_intel;
	Graphics_card_lenovo* g2 = new Graphics_card_lenovo;
	Memory_Module_intel* m1 = new Memory_Module_intel;
	Memory_Module_lenovo* m2 = new Memory_Module_lenovo;

	cout << "第一台电脑" << endl;
	computer* com = new computer(c1,m1,g1);
	com->work();
	cout << "********************************" << endl;
	cout << "第二台电脑" << endl;
	computer* com1 = new computer(c2, m2, g2);
	
	com1->work();
}
int main() {
	fun();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

左手的月光

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值