关于多态的学习总结

   关于多态的学习总结(主要指的是虚函数的部分)

多态的最大特点是:“一个操作,不同结果”。而构成它的必要条件则是,赋值兼容规则和函数的虚特性;
    赋值兼容规则指的是,在公有派生的前提下(C++中由基类到子类叫“派生”,反之,叫继承),基类指针可以指向子类的对象,具体点说,基类指针指向的是派生类的基类的部分(子类对象在创建之前,会先创建基类对象,所以,一个子类对象包含基类对象的部分和派生类的部分)。
    那么问题来了,既然基类指针指向的仅仅是基类的部分,那么也就是说,若派生类有一个和基类一样的函数,那么,该指针将不能直接访问该成员函数。因此,C++引进了虚函数这个东西,用来解决这个问题。
    对于虚函数来说,第一个肯定是要有virtual这个关键字,那么该成员函数就有了虚特性,那么要把它的虚特性表现出来这显然是不够的,C++中规定,该虚函数要表现出虚特性,必须要在它的子类中也有一样的成员函数。(“一样”指的是函数的返回值,函数名, 函数的参数列表即参数的个数和类型必须相同)。只有满足这些函数的虚特性就能表现出来了,而它的派生类中这个一样的函数被自动也说明为virtual。
    例如,有一个基类Base,它有三个派生类,D1,D2和D3,他们都有一个一样的fun函数,并在基类中用virtual说明了它;
那么,

<strong>                Base * p;   
		p = new D1();
		p->fun();
		p = new D2();
		p->fun();
		p = new D3();
 		p->fun();</strong>
也就是说,由于兼容性规则的存在,那么,对于基类指针p它可以指向不同的派生类对象,又由于函数的虚特性特点,它可以访问派生类中不同的fun();
    那么问题又来了,既然基类的fun()既然说明成了虚函数,那么通过多态是访问不到的。那么,基类的fun()的唯一作用就是想通过它来访问派生类的fun(),这就类似一个水管的接口,水流可以通过这个接口可以流到它的分支里,在C++中,这个基类的fun()就被叫做“类的接口”,既然是接口,那就是只是想通过它来访问某个子类。因此,对于虚函数C++又提出了两个概念:“空虚函数”和“纯虚函数”,即
<strong>        virtual void  fun(){} //空虚函数
	virtual void  fun() = 0; //纯虚函数</strong>
值得注意的是含有纯虚函数的类是不能创建对象的,那么,如果还想实现原来基类的功能,就可以直接再写一个派生类,用它来实现原来fun()的功能;
    虽然,可以通过匹配的角度访问它,即就是创建一个Base类的对象,用p指针指向它,那么,就可以访问它的Base的fun()了,但是,这明显的破坏了它的多态性,而多态性的提出,就是为了在增加功能时,只是采用扩展,而不采用修改类里的东西,来修改该功能的扩充,即“开闭原则”;
    下面是一个具体实例:
<span style="font-size:24px;"><strong>//工厂模式之“媳妇做饭问题 ” 
#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
//饭类 
class fan {							
	public:	
		virtual void dofan() = 0;   //做饭类的接口, 派生类的dofan函数被自动说明为virtual类型 
};
//糖拌西红柿 
class XHS : public fan{
	public: 
		void dofan() {
			cout << "糖拌西红柿\n";
		}
}; 
//棍棍面
class GGM : public fan{
	public: 
		void dofan() {
			cout << "棍棍面\n";
		}
}; 
//羊肉泡 
class YRP : public fan{
	public: 
		void dofan() {
			cout << "羊肉泡\n";
		}
}; 
//媳妇 
class wife{
	public:
		fan * p;
		wife (int n){
				switch (n){
				case 1: p = new XHS();
					break;
				case 2: p = new GGM();
					break;
				case 3: p = new YRP();
					break;
				default:
					cout << "抱歉,不会做你要吃的饭...\n"; 
			}
		}
};</strong></span>
如果按照上面的模式写,所有的饭都让一个媳妇来做,看起来好像满足了“开闭原则”,但是,实际上随着我们生活水平的不断提高,我还可能想吃米饭炒菜,虽然对于饭类来说,只是添一个米饭炒菜类就行,但对于媳妇类来说,就违反了“开闭原则”了;
    因此我们想到,对客户端即媳妇类使用多态,代码如下:
<span style="font-size:24px;"><strong>//工厂模式之“媳妇做饭问题 ” 
#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
//饭类 
class fan {							
	public:	
		virtual void dofan() = 0;   //做饭类的接口, 派生类的dofan函数被自动说明为virtual类型 
};
//糖拌西红柿 
class XHS : public fan{
	public: 
		void dofan() {
			cout << "糖拌西红柿\n";
		}
}; 
//棍棍面
class GGM : public fan{
	public: 
		void dofan() {
			cout << "棍棍面\n";
		}
}; 
//羊肉泡 
class YRP : public fan{
	public: 
		void dofan() {
			cout << "羊肉泡\n";
		}
}; 
//米饭炒菜
class MFCC : public fan{
	public:
		void dofan() {
			cout << "米饭炒菜\n";
		} 
}; 
//媳妇 
class wife {
	public:
		virtual void SWife(int n) = 0; //媳妇类的接口 
}; 
//大媳妇 
class DWife : public wife{
	public:
		fan * p;
		void SWife (int n){
				switch (n){
				case 1: p = new XHS();
					break;
				case 2: p = new GGM();
					break;
				case 3: p = new YRP();
					break;
				default:
					cout << "抱歉,不会做你要吃的饭...\n"; 
			}
		}
		~DWife(){
			p->dofan();
			delete p;
		}
};
//二媳妇
class EWife : public wife{
	public:
		fan * p;
		void SWife(int n){
			p = new MFCC();
		}
		~EWife(){
			p->dofan();	
			delete p;
		}
};</strong></span>

    这次看代码貌似好了,但可以试想一下,万一要是大媳妇生气了,不做饭了,那么凉拌西红柿,棍棍面以及羊肉泡就吃不到了,这就是违反了软件工程所提倡的“高内聚,低耦合”原则,具体来说,就是代码的那么解决的办法,就是降低它的耦合度,也就是说,一个媳妇只做一种饭,想吃下一个饭,只要派生出该饭的类,和它所对应的媳妇;
    代码如下:
<span style="font-size:24px;"><strong>//工厂模式之“媳妇做饭问题 ” 
#include <iostream>
using namespace std;
//饭类 
class fan {							
	public:	
		virtual void dofan() = 0;   //做饭类的接口, 派生类的dofan函数被自动说明为virtual类型 
};
//糖拌西红柿 
class XHS : public fan{
	public: 
		void dofan() {
			cout << "糖拌西红柿\n";
		}
}; 
//棍棍面
class GGM : public fan{
	public: 
		void dofan() {
			cout << "棍棍面\n";
		}
}; 
//羊肉泡 
class YRP : public fan{
	public: 
		void dofan() {
			cout << "羊肉泡\n";
		}
}; 
//米饭炒菜
class MFCC : public fan{
	public:
		void dofan() {
			cout << "米饭炒菜\n";
		} 
}; 
//媳妇 
class wife {
	public:
		virtual void SearchWife() = 0; //媳妇类的接口 
}; 
//大媳妇 
class DWife : public wife{
	public:
		fan * p;
		void SearchWife(){
			p = new XHS();
		}
		~DWife(){
			p->dofan();	
			delete p;
		}
}; 
//二媳妇 
class EWife : public wife{
	public:
		fan * p;
		void SearchWife(){
			p = new GGM();
		}
		~EWife(){
			p->dofan();	
			delete p;
		}
}; 
//三媳妇
class SWife : public wife{
	public:
		fan * p;
		void SearchWife(){
			p = new YRP();
		}
		~SWife(){
			p->dofan();	
			delete p;
		}
}; 
//四媳妇
class SiWife : public wife{
	public:
		fan * p;
		void SearchWife(){
			p = new YRP();
		}
		~SiWife(){
			p->dofan();	
			delete p;
		}
}; 
//五媳妇
class WWife : public wife{
	public:
		fan * p;
		void SearchWife(){
			p = new MFCC();
		}
		~WWife(){
			p->dofan();	
			delete p;
		}
}; </strong></span>
经过这个问题的练习,不难发现多态的重要性,以及它的应用,以上就是本人对多态的理解。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值