C++11学习 virtual(虚函数)的用法

Virtual虚函数

  • 在面向对象的C++语言中,虚函数(virtual function)是一个非常重要的概念。因为它充分体现了面向对象思想中的继承和多态性这两大特性,在C++语言里应用极广。
  • 多态性:其含义就是多种形式;将具有继承关系的多种类型称之为多态模型,因为使用者可以使用这种类型的多种形式,但是不需要在意他们之间的差异。归根结底,引用或指针的静态类型与动态类型的不一致是C++语言支持多态性的根本原因。
  • 在派生类中覆盖了某一个虚函数,可以再一次使用virtual关键字指出该函数的性质。如果将一个函数声明为虚函数,那么这个函数在所有的派生类别中都是虚函数。一个派生类的函数如果覆盖了某个继承而来的虚函数,则它的形参类型必须要和被覆盖的函数完全一致。同样,派生类中的虚函数返回的类型必须和基类的类型是一致的,但是这个存在一个例外。当类的虚函数返回的类型是类本身的指针或者引用的时候,上述规则无效。
  • 什么是虚函数呢?虚函数是指一个类中你希望重载的成员函数,当你用一个基类指针或引用指向一个继承类对象的时候,你调用一个虚函数,实际调用的是继承类的版本。 ——摘自MSDN
#include <cstring>
#include <string>
#include <iostream>
#include <stdio.h>
#include <conio.h>
using namespace std;

class Parent{
    public:
        char data[20];
        void Function1();
        virtual void Function2(); //这里的Function2是虚拟函数

}parent;

void Parent::Function1() {
    printf("This is parent,function1\n");
}

void Parent::Function2() {
    printf("This is parent,function2\n");
}

class Child:public Parent{
    void Function1();
    void Function2();
}child;

void Child::Function1(){
    printf("This is child,function1\n");
}

void Child::Function2() {
    printf("This is child,function2\n");
}
int main(int argc,char* argv[]){
    Parent *p;//定义了一个基类指针
    if(_getch() == 'c'){
        p = &child;  // 如果用户输入一个小写的字母c,指向继承类对象
    }else{
        p = &parent; // 否则指向一个基类对象
    }

    p->Function1();  // 这里编译时会直接给出Parent::Function1()的入口地址
    p->Function2();  // 注意这里,执行的是哪一个Function2?

}

  • 为什么会有第一行的结果呢?因为是用一个Parent类的指针调用函数Fuction1(),虽然实际上这个指针指向的是Child类的对象,但编译器无法知道这一事实(直到运行的时候,程序才可以根据用户的输入判断出指针指向的对象),它只能按照调用Parent类的函数来理解并编译,所以看到了第一行的结果。
  • 那么第二行的结果又是怎么回事呢?注意到,Function2()函数在基类中被virtual关键字修饰,也就是说,它是一个虚函数。虚函数最关键的特点是“动态联编”,它可以在运行时判断指针指向的对象,并自动调用相应的函数。
  • 如果在运行上面的程序时任意输入一个非c的字符,结果如下:

  • 请注意看第二行,它的结果出现了变化。程序中仅仅调用了一个Function2()函数,却可以根据用户的输入自动决定到底调用基类中的Function2还是继承类中的Function2,这就是虚函数的作用。在MFC中,很多类都是需要继承的,它们的成员函数很多都要重载,比如编写MFC应用程序最常用的CView::OnDraw(CDC*)函数,就必须重载使用。把它定义为虚函数(实际上,在MFC中OnDraw不仅是虚函数,还是纯虚函数),可以保证时刻调用的是用户自己编写的OnDraw。虚函数的重要用途在这里可见一斑。
  • PS:一定要注意“静态联翩 ”和“ 动态联编 ”的区别,对于我来说,若没有在VC6.0中亲自去测试,凭自己的感觉,当在键盘中输入“c”时,因为虽然实际上这个指针指向的是Child类的对象,但编译器无法知道这一事实,它只能按照调用Parent类的函数来理解并编译,所以我们看到了第一行的结果。第二行中调用了子类的function2,完全是因为virtual 的功能,virtual实现了动态联编,它可以在运行时判断指针指向的对象,并自动调用相应的函数。当然,如果执行的是p=&parent; 这一句,该指针很明显的是指向父类,那么肯定调用的是父类的方法 

final和override说明符

  • 派生类如果定义了一个函数与基类的虚函数的名字相同但是形参列表不同,这仍然是一个合法的行为,需要使用关键字override来说明派生类中的虚函数。
  • 如果将某个函数指定为final,则之后任何尝试覆盖该函数的操作都会引发错误。

虚函数和默认实参

  • 虚函数使用默认实参,则基类和派生类中定义的默认实参最好一致。

回避虚函数的机制

  • 如果希望对于虚函数的调用不是动态的绑定,而是强迫其执行虚函数的某一个特定的版本。可以使用作用域运算符来实现
  • double undiscounted = baseP->Quote::net_price(43);//强行调用基类中定义的函数版本,而不管baseP的动态类型是什么
  • 通常情况下,只有成员函数(或友元函数)中的代码才需要使用作用域运算符来回避虚函数的机制。如果一个派生类虚函数需要调用它的基类版本,但是没有使用作用域运算符,则在运行的时候该调用会被解析成对于派生类的版本自身的调用,从而导致无限的递归。

 

 

 

 

 

开题报告 经过大学四年理论课程的学习,以及校内校外的实践,极大的丰富了自身的理论基础,并且也具备了一些处理简单问题的能力,但即将踏上社会的我深知这还远远不够,因此我利用了毕业设计的机会,在老师的指导下去完成一个具有挑战性的,其具体应用及社会服务相结合的项目,深知通过对它的开发,将对我的能力有更高层次的突破。 开发软件的一个目的是针对目前普遍的图书管理系统存在的功能不全,操作复杂,系统要求高等一系列问题,而设想一个具有个性化的图书管理系统。该管理系统与MIS系统相联系,在图书馆内部建成可靠,方便,并且功能齐全的MIS系统。从而在图书馆对新旧书的反应;对书籍借阅的管理能力;对读者和图书馆工作人员的管理能力;对图书馆管理人员软件操作的适应时间和操作感觉这些方面都将大大的提高。当然对该软件的态度是渴望获得显著的社会效益。 开发软件的另一个目的是使其具有强大的实用价值,即它可以满足中小型图书馆的借阅与管理的需要。在一般的学校与科研机构,其下属的很多分支的研究中心,试验中心,各个学院,它们往往都有着自己的规模较大的图书资料室。而这些图书资料室由于本身规模不大因此其对书籍或资料的管理模式一般都比较旧,而且在没有能力也没有必要引进大型的图书馆管理软硬件的基础上,寻求一个针对中小型图书资料室的管理软件是必要的。 这种管理软件对硬件的要求很低,一般有一个比较简单的服务器与PC机组成的网络即可,再加上使用比较廉价、性能不错的软件,这样就可以以较低的成本来实现一个足够使用的功能,而这种模式也正满足了那种中小型资料室,图书馆的要求。但是目前对这种管理软件的开发还处于一种比较原始的阶段。开发者往往都是出于资金和时间的顾虑使用比较陈旧的技术,并且各为己见,并且很少涉及网络。可是当今是一个网络化的社会,像资料室,图书馆这样的信息机构不能与网络联系起来岂不可惜,再加上如今单机版的图书管理软件多如牛毛,去开发一个类似的软件无疑是一种在时间上、精神上和资源上的极大浪费。所以出于多方面的考虑觉得有必要为这种有需要的中小型图书馆,资料室开发一种基于网络的图书资料管理软件。 项目的具体目的: 1. 实现图书馆对外借书,还书的简易操作,提高图书馆对最平凡工作的效率。 2. 实现图书馆对所藏图书的按类别,书名等多方面的查询,最大的方便读者和图书馆工作人员对所需图书的查询。 3. 建立图书馆外借读者数据库,方便工作人员对读者进行有效管理。 4. 建立图书馆工作人员数据库,限定每个工作人员对软件操作的权限,最大限度的保护数据库。 5. 实现图书馆对新书入库,旧书注销的简单处理,并且建立书籍档案,方便进货。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值