- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
[从业资格考试]9 多态性和虚函数
多态性是面向对象程序设计的重要特征之一。 多态性是指相同的对象收到相同的消息时,或不同的对象收到相同的消息时,产生不同的处理结果。 重载是一种多态性,使一个对象调用相同的成员函数时,会由参数不同而产生不同的调用结果。 派生类既可以继承基类中定义过的成员函数,也可以覆盖基类中定义过的成员函数,这样,派生类对象调用一个成员函数时,就会因派生类中是否覆盖了基类中成员函数而有不同的调用结果。 另外,派生类还可以重载基类中定义过的成员函数,这样,派生类对象调用一个成员函数时,就会由参数不同产生不同的调用结果。 但是,在程序设计中仅仅通过派生类是否覆盖基类定义过的成员函数提供的多态性有时不够灵活。 对一个类层次来说,同样一个成员函数的调用,如果程序中动态确定的对象不同,则调用的成员函数不同,会为程序设计带来更大的灵活性,这种多态性称做运行时的多态性。 多态的实现: 函数重载 运算符重载 虚函数 联编(binding):是指计算机程序自身彼此关联的过程,将一个函数调用链接上相应的函数体代码,这一过程称为函数联编。 静态联编:联编工作在编译连接阶段完成的情况。如果在程序的编译阶段就已经确定函数调用和函数体代码之间的关系,这种联编过程为静态联编。 动态联编:联编在程序运行阶段完成的情况。当程序运行时再确定函数调用语句和函数体代码的关系,这种联编为动态联编。 定义一坐标点类和圆类,这两个类能计算点和圆的面积。 对于联编过程,如何确定采用静态联编还是采用动态联编,这是实现联编多态性的关键。C++的虚函数机制是实现动态联编 的基础。 请看下面绘制图形的例子: 虚函数的说明形式 virtual 类型说明符 函数名(参数表) 1、虚函数必须是类的非静态成员函数 2、派生类中定义的成员函数如果和基类中说明的虚函数 的函数名相同,函数参数个数、对应类型相同,返回值类型相同,该成员函数即使没有说明为虚函数,其也自动成为虚函数。 3、只有通过指针和引用标识对象来操作虚函数,才能实现动态联编。通过对象操作虚函数采用静态联编方式调用虚函数。 虚函数的访问权限 派生类中所定义的虚函数的访问权限不影响对它进行动态联编。即只要基类中定义的虚函数的访问权限为public,则派生类中的虚函数即使是private成员,通过指向基类对象的指针或对象引用亦可对派生类中的私有虚成员函数进行动态联编。 在成员函数中调用虚函数 在构造函数中调用虚函数 在成员函数中调用虚函数 在一个基类或派生类的成员函数中可以直接调用该类等级中的虚函数。 void main() { B b; b.act2(); } 该程序执行后的输出结果是什么?为什么? 如果 A::act2()改为: void act2( ){A::act1();},输出结果会为什么呢? 如果将 A::act2()改为: void act2( ){this-act1();},输出结果会为什么呢? 在成员函数中调用虚函数 在构造函数中调用虚函数 在构造函数中调用虚函数 在构造函数中调用虚函数时采用静态联编,即构造函数中调用的虚函数是自己类中或基类中定义的函数,而不是任何派生类中重新定义的虚函数。 虚函数和派生类对基类成员函数覆盖的区别 虚函数也像派生类对基类成员函数的覆盖那样,在派生类中覆盖了基类的成员函数,而且要求参数个数、参数类型和返回类型完全一样。 对于派生类对基类成员函数的覆盖来说,调用成员函数的对象在程序编译时就已确定,不能在程序运行时改变。 对于虚函数,调用成员函数的对象要在程序运行时才确定,要根据对象指针当前指向的对象是基类对象还是派生类对象来决定。 虚析构函数 在C++语言中,虚构造函数是没有意义的,但虚析构函数是有意义的。 如果外部程序使用new运算符定义了动态对象,则当外部程序结束时,要使用delete运算符删除该动态对象。但是,如果外部程序利用赋值兼容原则,把动态申请的派生类对象地址赋给了基类对象指针,由于delete运算符隐含有对析构函数的自动调用,因些此时自动调用的必定是基类的析构函数,这就有可能引起内存泄露问题。 解决的方法是在存在虚函数的类层次中,在析构函数定义前也添加关键字virtual,即把析构函数也设计成虚析构函数。这样,delete运算符就能根据当前对象指针指向的是基类对象还是派生类对象,来自动调用基类的析构函数或是派生类的析构函数,从而避免出现内存泄露问题。 #include iostream.h #include string.h class A { public: A(){} virtual ~A() { cout基类的析构函数endl; } }; class AA:public
文档评论(0)