派生一个类的原因并非总是为了继承或是添加新的成员,有时是为了重新定义基类的成员,使得基类成员“获得新生”。面向对象的程序设计真正的力量不仅仅是继承,而且还在于允许派生类对象像基类对象一样处理,其核心机制就是多态和动态联编。
(一)多态性
多态是指同样的消息被不同的对象接收时导致不同的行为。所谓消息是指对类成员函数的调用,不同的行为是指的不同的实现,也就是调用了不同的函数。
1)多态的分类
广义上说,多态性是指一段程序能够处理多种类型对象的能力。在C++中,这种多态性可以通过重载多态(函数和运算符重载),强制重载(类型强制转换),类型参数化多态(模板)
,包含多态(继承与虚函数)四种方式来实现。类型参数化多态和包含多态称为一般多态性,是用来系统地刻画语义上相关的一组类型;重载多态和强制多态性称为特殊多态性,用来刻画语义上无关连的类型间关系。
C++中采用虚函数实现包含多态。虚函数为C++提供了更为灵活的多态机制,这种多态性在程序运行时才能够确定,因此虚函数是多态性的精华,至少含有一个虚函数的类称为多态类。包含多态在面向对象的程序设计中使用很频繁。
2)静态联编
联编又称为绑定,就是将模块或函数合并在一起生成可执行代码的处理过程,同时对每个模块或函数分配内存地址,对外部访问也提供正确的内存地址。
在编译阶段就将函数实现与函数调用绑定起来称为静态联编。静态联编在编译阶段就必须了解所有函数与模块执行所需要的信息,它对函数的选择是基于指向对象的指针(或引用)的类型。在C语言中所有的联编都是静态联编;C++中一般情况也是静态联编。
class Point{ public: void area(){cout<<"point";} }; class Circle:public Point{ public: void area(){cout<<"circle";} }; Point a; Circle c; a.area(); //调用a.Point::area() c.area(); //调用c.Circle::area(),免费精选名字大全支配规则 Point * pc=&c,&rc=c; //上篇所讲的赋值兼容性规则 pc->area(); //调用pc->Point::area() rc.area(); //调用rc.Point::area()
3)动态联编
如果程序在运行时候才进行函数实现和函数调用的绑定称为动态联编。以上面的例子为例,在编译时如果只根据兼容性规则检查它的合理性,即检查它是否符合派生类对象地址可以赋值给基类指针变量的条件。至于pc->area()调用哪个函数等到程序运行到这里才做决定。如果希望其调用Circle::area(),那么需要将Point类的area()函数指定为虚函数。定义形式为:
virtual void area(){cout<<"point";}
当编译器编译含有虚函数的类时候,将为他建立一个虚函数表VTABLE,它相当于一个指针数组,存放每一个虚函数的入口地址。编译器为该类增减一个额外的数据成员,这个数据成员是一个指向虚函数表的指针,称为vptr。
如果派生类没有重写这个虚函数,则派生类的虚函数列表里元素指向的地址就是基函数area()的地址,即派生类仅仅继承基类的虚函数
如果派生类重新写这个虚函数如下:
virtual void area() {cout<<"circle";}
那么这时编译器将派生类虚函数表里的元素指向Circle::area()
编译器为含有虚函数的对象先建立一个函数入口地址,这个地址用来存放指向虚函数表的指针vptr,然后按照类中虚函数的声明次序一一填入函数指针。当调用虚函数时候,先通过vptr找到虚函数表,然后找出虚函数真正的地址。
派生类能够继承基类的虚函数表,而且只要是和基类同名(参数也相同)的成员函数,无论是否使用virtual声明,它们都自动生成虚函数。如果派生类没有改写继承基类的虚函数,则函数指针将调用基类的虚函数。
(二)虚函数
1)虚函数定义
虚函数只是类中的一个成员函数,且不能是静态的。在成员函数定义或声明之前加上关键字virtual,即定义了虚函数:
class类名{ ... virtual 返回类型 函数名 (形式参数列表)//虚函数 ... }; class Point { virtual void area (); //虚函数声明 virtual double volumn(){} //虚函数定义 };
需要注意virtual关键字只在类体中使用。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/483686.html