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;
}
编译结果如下。不能将基类对指针转换为子类指针,因为子类对象一般比基类对象要大,所以这种转换可能会造成访问越界,这大概是编译器报错的原因吧。
暂时更新到这,后续有新想法了再更新。