王朝网络
分享
 
 
 

C++中类的多态与虚函数的使用

王朝c/c++·作者佚名  2008-06-01
宽屏版  字体: |||超大  

类的多态特性是支持面向对象的语言最主要的特性,有过非面向对象语言开发经历的人,通常对这一章节的内容会觉得不习惯,因为很多人错误的认为,支持类的封装的语言就是支持面向对象的,其实不然,

Visual BASIC 6.0 是典型的非面向对象的开发语言,但是它的确是支持类,支持类并不能说明就是支持面向对象,能够解决多态问题的语言,才是真正支持面向对象的开发的语言,所以务必提醒有过其它非面向对象语言基础的读者注重!

多态的这个概念稍微有点模糊,假如想在一开始就想用清楚用语言描述它,让读者能够明白,似乎不太现实,所以我们先看如下代码://例程1

#include <iostream>

using namespace std;

class Vehicle

{

public:

Vehicle(float speed,int total)

{

Vehicle::speed=speed;

Vehicle::total=total;

}

void ShowMember()

{

cout<<speed<<""<<total<<endl;

}

PRotected:

float speed;

int total;

};

class Car:public Vehicle

{

public:

Car(int aird,float speed,int total):Vehicle(speed,total)

{

Car::aird=aird;

}

void ShowMember()

{

cout<<speed<<""<<total<<""<<aird<<endl;

}

protected:

int aird;

};

void main()

{

Vehicle a(120,4);

a.ShowMember();

Car b(180,110,4);

b.ShowMember();

cin.get();

}在c++中是答应派生类重载基类成员函数的,对于类的重载来说,明确的,不同类的对象,调用其类的成员函数的时候,系统是知道如何找到其类的同名成员,上面代码中的a.ShowMember();,即调用的是Vehicle::ShowMember(),b.ShowMember();,即调用的是Car::ShowMemeber();。

更多内容请看C/C++技术专题专题,或

但是在实际工作中,很可能会碰到对象所属类不清的情况,下面我们来看一下派生类成员作为函数参数传递的例子,代码如下:

//例程2

#include <iostream>

using namespace std;

class Vehicle

{

public:

Vehicle(float speed,int total)

{

Vehicle::speed=speed;

Vehicle::total=total;

}

void ShowMember()

{

cout<<speed<<""<<total<<endl;

}

protected:

float speed;

int total;

};

class Car:public Vehicle

{

public:

Car(int aird,float speed,int total):Vehicle(speed,total)

{

Car::aird=aird;

}

void ShowMember()

{

cout<<speed<<""<<total<<""<<aird<<endl;

}

protected:

int aird;

};

void test(Vehicle &temp)

{

temp.ShowMember();

}

void main()

{

Vehicle a(120,4);

Car b(180,110,4);

test(a);

test(b);

cin.get();

}例子中,对象a与b分辨是基类和派生类的对象,而函数test的形参却只是Vehicle类的引用,按照类继续的特点,系统把Car类对象看做是一个Vehicle类对象,因为Car类的覆盖范围包含Vehicle类,所以test函数的定义并没有错误,我们想利用test函数达到的目的是,传递不同类对象的引用,分别调用不同类的,重载了的,ShowMember成员函数,但是程序的运行结果却出乎人们的意料,系统分不清楚传递过来的基类对象还是派生类对象,无论是基类对象还是派生类对象调用的都是基类的ShowMember成员函数。

更多内容请看C/C++技术专题专题,或

为了要解决上述不能正确分辨对象类型的问题,c++提供了一种叫做多态性(polymorphism)的技术来解决问题,对于例程序1,

这种能够在编译时就能够确定哪个重载的成员函数被调用的情况被称做先期联编(early binding),而在系统能够在运行时,能够根据其类型确定调用哪个重载的成员函数的能力,称为多态性,或叫滞后联编(late binding),下面我们要看的例程3,就是滞后联编,滞后联编正是解决多态问题的方法。

代码如下://例程3

#include <iostream>

using namespace std;

class Vehicle

{

public:

Vehicle(float speed,int total)

{

Vehicle::speed = speed;

Vehicle::total = total;

}

virtual void ShowMember()//虚函数

{

cout<<speed<<""<<total<<endl;

}

protected:

float speed;

int total;

};

class Car:public Vehicle

{

public:

Car(int aird,float speed,int total):Vehicle(speed,total)

{

Car::aird = aird;

}

virtual void ShowMember()//虚函数,在派生类中,由于继续的关系,这里的virtual也可以不加

{

cout<<speed<<""<<total<<""<<aird<<endl;

}

public:

int aird;

};

void test(Vehicle &temp)

{

temp.ShowMember();

}

int main()

{

Vehicle a(120,4);

Car b(180,110,4);

test(a);

test(b);

cin.get();

}多态特性的工作依靠虚函数的定义,在需要解决多态问题的重载成员函数前,加上virtual要害字,那么该成员函数就变成了虚函数,从上例代码运行的结果看,系统成功的分辨出了对象的真实类型,成功的调用了各自的重载成员函数。 多态特性让程序员省去了细节的考虑,提高了开发效率,使代码大大的简化,当然虚函数的定义也是有缺陷的,因为多态特性增加了一些数据存储和执行指令的开销,所以能不用多态最好不用。

更多内容请看C/C++技术专题专题,或

虚函数的定义要遵循以下重要规则:

1.假如虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual要害字,也是不会进行滞后联编的。

2.只有类的成员函数才能说明为虚函数,因为虚函数仅适合用与有继续关系的类对象,所以普通函数不能说明为虚函数。

3.静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。

4.内联(inline)函数不能是虚函数,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义定义,但是在编译的时候系统仍然将它看做是非内联的。

5.构造函数不能是虚函数,因为构造的时候,对象还是一片位定型的空间,只有构造完成后,对象才是具体类的实例。

6.析构函数可以是虚函数,而且通常声名为虚函数。

说明一下,虽然我们说使用虚函数会降低效率,但是在处理器速度越来越快的今天,将一个类中的所有成员函数都定义成为virtual总是有好处的,它除了会增加一些额外的开销是没有其它坏处的,对于保证类的封装特性是有好处的。对于上面虚函数使用的重要规则6,我们有必要用实例说明一下,为什么具备多态特性的类的析构函数,有必要声明为virtual。

代码如下:#include <iostream>

using namespace std;

class Vehicle

{

public:

Vehicle(float speed,int total)

{

Vehicle::speed=speed;

Vehicle::total=total;

}

virtual void ShowMember()

{

cout<<speed<<""<<total<<endl;

}

virtual ~Vehicle()

{

cout<<"载入Vehicle基类析构函数"<<endl;

cin.get();

}

protected:

float speed;

int total;

};

class Car:public Vehicle

{

public:

Car(int aird,float speed,int total):Vehicle(speed,total)

{

Car::aird=aird;

}

virtual void ShowMember()

{

cout<<speed<<""<<total<<""<<aird<<endl;

}

virtual ~Car()

{

cout<<"载入Car派生类析构函数"<<endl;

cin.get();

}

protected:

int aird;

};

void test(Vehicle &temp)

{

temp.ShowMember();

}

void DelPN(Vehicle *temp)

{

delete temp;

}

void main()

{

Car *a=new Car(100,1,1);

a->ShowMember();

DelPN(a);

cin.get();

}从上例代码的运行结果来看,当调用DelPN(a);后,在析构的时候,系统成功的确定了先调用Car类的析构函数,而假如将析构函数的virtual修饰去掉,再观察结果,会发现析构的时候,始终只调用了基类的析构函数,由此我们发现,多态的特性的virtual修饰,不单单对基类和派生类的普通成员函数有必要,而且对于基类和派生类的析构函数同样重要。

更多内容请看C/C++技术专题专题,或

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有