关于多态的学习总结

来源:互联网 发布:手机淘宝服务中心 编辑:程序博客网 时间:2024/04/29 08:14

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

多态的最大特点是:“一个操作,不同结果”。而构成它的必要条件则是,赋值兼容规则和函数的虚特性;
    赋值兼容规则指的是,在公有派生的前提下(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 0
原创粉丝点击