c++ 类的多态

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;
}

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


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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值