c++ 类的多态

来源:互联网 发布:json里面含有html标签 编辑:程序博客网 时间:2024/04/29 16:20

1. 何为多态

    多态(polymorphisn),即多种不同的形态。在c++中,指一般的函数或类的接口,在运行时,因为外部的因素变化,执行不同的过程,产生不同的结果。

   (1) 编译时绑定。

         这是函数重载实现多态的情况。多个函数有相同的名字,不过参数和返回值不同,在编译时函数名称和调用地址就已经确定。运行时,依据函数名和参数确定调用哪个接口。

   (2) 运行时绑定

         这是类的接口实现多态的情况。基类和子类中的接口名称和参数完全一致,编译时接口的名称和调用地址的关系并不确定,运行时,依据类的具体类型来确定调用哪个接口。

   后面仅对类实现多态的情况进行解析

2. 多态的作用

   (1). 通过一个接口,实现不同的功能。

         定义基类的接口为虚函数,子类继承此接口,并各自实现此接口。指向子类的基类指针,执行基类的接口调用,便可以调用子类的接口实现实现,不用太多改变,就可以进行  功能的扩展。

         譬如对于游戏的后端而言,在一个处理逻辑的主循环中,一个基类的指针顺序调用其三个接口 on_init(),on_active(),on_finish(),通过传入不同的子类指针,就可以调用实现不同的功能。

        要进行功能扩展时,只需要实现一个child继承至base,并实现on_init, on_active,on_finish,并注册一个的消息ID与此类关联即可。

class base {public:virtual on_init();virtual on_active();virtual on_finish();};class child_1:public base(){public:virtual on_init();virtual on_active();virtual on_finish();};class child_2:public base(){public:virtual on_init();virtual on_active();virtual on_finish();};base* p = NULL;// 待处理的消息// 设置两个消息,1、2// 分别对应child_1的处理和child_2的处理vector<int> msg;msg.push_back(1);msg.push_back(2);int msg_count = msg.size();// 消息ID和处理类的关联map<int, base*> msg_child;// 注册消息ID与处理类的关联msg_child.insert(make_pair(1, new child_1()));msg_child.insert(make_pair(2, new child_2()));map<int, base*>::iterator it;while(msg_count--){// 消息与对应的处理类it = msg_child.find(msg[msg_count]);....p = it->second;// 子类的处理过程if(p){p->on_init();...p->on_active();...p->on_finish();...}...}

3. 多态的实现

   c++类的多态,通过如下方式来实现:

   (1)定义一个基类,并声明某个接口为虚函数,用 virtual 修饰。

   (2)定义一个子类,public 继承此基类,并重新实现基类中的虚函数接口,参数、返回值必须一致。

   (3)定义一个基类的指针,赋予基类或子类的值,调用声明为虚函数的接口(或通过引用)。

   一个技术点

     基类中声明为虚函数的接口,子类中此接口自动为虚函数,无需显示声明。基类及其子类以及子类的子类的这个接口,都将具有多态性。

#include <stdlib.h>#include <iostream>using namespace std;class fruit{public:virtual void name(){cout << "----fruit----" << endl;}};class orange:public fruit{public:void name(){cout << "----orange----" << endl;}};class orange_yichang:public orange{public:void name(){cout << "----orange_yichang----" << endl;}};int main(int argc, char **argv){fruit FRUIT;orange ORANGE;orange_yichang ORANGE_YICHANG;fruit *test = NULL;orange *orange_test = NULL;test = &FRUIT;test->name();test = &ORANGE;test->name();test = &ORANGE_YICHANG;test->name();orange_test = &ORANGE_YICHANG;orange_test->name();return 0;}

上例中,基类 fruit,接口 name 声明为虚函数。子类 orange 继承至 fruit,orange_yichang 继承至orange。 

执行结果如下。可见,虽然子类 orange 的接口 name 未显示声明为虚函数,但 orange_yichang 的 name 接口也具有多态行。

4. 多态的几个实现要点,不满足时的验证。

(1)接口未声明为虚函数。   

#include <stdlib.h>#include <iostream>using namespace std;class fruit{public:void name(){cout << "------class fruit-------" << endl; }};class orange:public fruit{public:void name(){cout << "------class orange-------" << endl; }};int main(int argc, char **argv){fruit FRUIT;orange ORANGE;fruit *test = NULL;test = &FRUIT;cout << "Point to Fruit";test->name();test = &ORANGE;cout << "Point to Orange"; test->name();return 0;}

执行结果如下。可见虽然基类指针指向的是不同的对象,但调用的接口并没有多态性,都只调用了基类的接口。


(2)非 public 继承

#include <stdlib.h>#include <iostream>using namespace std;class fruit{public:void name(){cout << "------class fruit-------" << endl; }};class orange: private fruit{public:void name(){cout << "------class orange-------" << endl; }};int main(int argc, char **argv){fruit FRUIT;orange ORANGE;fruit *test = NULL;test = &FRUIT;cout << "Point to Fruit";test->name();test = &ORANGE;cout << "Point to Orange";test->name();return 0;}

编译时的错误如下。由于采用了private继承的方式,基类的所有成员和接口转为private的类型。子类的实例化对象,无法访问基类对象,所以无法进行指针的转换。


(3)定义子类的指针,将基类和子类的指针赋予它,调用动态接口

#include <stdlib.h>#include <iostream>using namespace std;class fruit{public:virtual void name(){cout << "------class fruit-------" << endl; }};class orange:public fruit{public:virtual void name(){cout << "------class orange-------" << endl; }};int main(int argc, char **argv){fruit FRUIT;orange ORANGE;orange *test = NULL;test = &FRUIT;cout << "Point to Fruit";test->name();test = &ORANGE;cout << "Point to Orange";test->name();return 0;}

编译结果如下。不能将基类对指针转换为子类指针,因为子类对象一般比基类对象要大,所以这种转换可能会造成访问越界,这大概是编译器报错的原因吧。


暂时更新到这,后续有新想法了再更新。

原创粉丝点击