Cpp--虚函数的存在

来源:互联网 发布:阿里云免费证书配置 编辑:程序博客网 时间:2024/06/05 21:55

1.虚函数基础:

定义:在某基类中声明为 virtual 并在一个或多个派生类中被重新定 义的成员函数

用法格式:virtual 函数返回类型 函数名(参数表) {函数体}

作用:它是实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数的基础。

#include <iostream>#include <string>using namespace std;//声明基类Studentclass Student{public:   Student(int, string,float);  //声明构造函数   void display( );//声明输出函数protected:  //受保护成员,派生类可以访问   int num;   string name;   float score;};//Student类成员函数的实现Student::Student(int n, string nam,float s)//定义构造函数{   num=n;   name=nam;   score=s;}void Student::display( )//定义输出函数{   cout<<"num:"<<num<<"\nname:"<<name<<"\nscore:"<<score<<"\n\n";}//声明公用派生类Graduateclass Graduate:public Student{public:   Graduate(int, string, float, float);//声明构造函数   void display( );//声明输出函数private:float pay;};// Graduate类成员函数的实现void Graduate::display( )//定义输出函数{   cout<<"num:"<<num<<"\nname:"<<name<<"\nscore:"<<score<<"\npay="<<pay<<endl;}Graduate::Graduate(int n, string nam,float s,float p):Student(n,nam,s),pay(p){}//主函数int main(){   Student stud1(1001,"Li",87.5);//定义Student类对象stud1   Graduate grad1(2001,"Wang",98.5,563.5);//定义Graduate类对象grad1   Student *pt=&stud1;//定义指向基类对象的指针变量pt   pt->display( );   pt=&grad1;   pt->display( );   return 0;}

现在用同一个指针变量(指向基类对象的指针变量),不但输出了学生stud1的全部数据,而且还输出了研究生grad1的全部数据,说明已调用了grad1的display函数。用同一种调用形式“pt->display()”,而且pt是同一个基类指针,可以调用同一类族中不同类的虚函数。这就是多态性,对同一消息,不同对象有 不同的响应方式。

2.定义虚函数的限制:

2.1 类的成员函数不能定义为虚函数,类的成员函数中静态成员函数和构造函数也不能定义为虚函数,但可以将析构函数定义为虚函数。实际上,优秀的程序员常常把基类的析构函数定义为虚函数。因为,将基类的析构函数定义为虚函数后,当利用delete删除一个指向派生类定义的对象指针时,系统会调用相应的类的析构函数。而不将析构函数定义为虚函数时,只调用基类的析构函数。

2.2 只需要在声明函数的类体中使用关键字“virtual”将函数声明为虚函数,定义函数时不需要使用关键字“virtual”。
2.3 当将基类中的某一成员函数声明为虚函数后,派生类中的同名函数(函数名相同、参数列表完全一致、返回值类型相关)自动成为虚函数。
2.4 如果声明了某个成员函数为虚函数,则在该类中不能出现和这个成员函数同名并且返回值、参数个数、类型都相同的非虚函数。在以该类为基类派生类中,也不能出现这种同名函数。

3.虚函数与派生类:

3.1 派生类一般会重新定义所继承的虚函数,如果派生类没有定义某个虚函数,则使用基类中定义的版本。派生类必须对想要重定义的每个继承成员进行声明。
3.2 派生类中虚函数的声明必须与基类中的定义方式完全匹配,例外:返回对基类型的引用(或指针)的虚函数。派生类中的虚函数可以返回基类函数所返回类型的派生类的引用或指针(不太懂,待深究)。

4.动态绑定:

4.1 C++中,通过基类的引用或指针调用虚函数时,发生动态绑定。引用(或指针)既可以指向基类对象也可以指向派生类对象,这一事实是动态绑定的关键。用引用(或指针)调用的虚函数在运行时确定,被调用的函数是引用(或指针)所指对象的实际类型所定义的。
通过动态绑定,我们能够编写程序使用继承层次中任意类型的对象,无须关注对象的具体类型,使用这些类的程序无须区分函数是在基类还是在派生类中定义的。
4.2 触发动态绑定必须满足两个条件:只有指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数,非虚函数不进行动态绑定;必须通过基类类型的引用或指针进行函数调用。(必须理解在使用继承层次中某一类型的对象的引用或指针会发生什么)

5.覆盖虚函数机制:

为了派生类虚函数调用基类中的版本,我们有时需要使用覆盖虚函数机制并强制函数调用使用虚函数的特定版本,这时可以使用作用域操作符:
Item_base *baseP = &derived;double d = baseP->Item_base::net_price(42);
这段代码强制将net_price调用确定为Item_base中定义的版本,该调用将在编译时确定。

6.纯虚函数:

6.1 纯虚函数是一种特殊的虚函数,在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。这就是纯虚函数的作用。

6.2 纯虚函数可以让类先具有一个操作名称,而没有操作内容,让派生类在继承时再去具体地给出定义。凡是含有纯虚函数的类叫做抽象类。这种类不能声明对象,只是作为基类为派生类服务。除非在派生类中完全实现基类中所有的的纯虚函数,否则,派生类也变成了抽象类,不能实例化对象。

6.3 在基类中实现纯虚函数的方法是在函数原型后加“=0”

6.4 纯虚函数只有函数的名字而不具备函数的功能,不能被调用。它只是通知编译系统:“在这里声明一个虚函数,留待派生类中定义”。在派生类中对此函数提供定义后,它才能具备函数的功能,可被调用。纯虚函数的作用是在基类中为其派生类保留一个函数的名字,以便派生类根据需要对它进行定义。如果在基类中没有保留函数名字,则无法实现多态性。如果在一个类中声明了纯虚函数,而在其派生类中没有对该函数定义,则该虚函数在派生类中仍然为纯虚函数。(具体例程待补充)


接下来再补充一个虚函数的例子

#include "stdio.h"  #include <iostream>    using namespace std;    class A    {    public:        virtual void print()        { cout << "A::print()" <<endl;}    };    class B: public A    {    public:        virtual void print()        { cout << "B::print()" <<endl;}    };    class C: public A    {    public:        virtual void print()        { cout << "C::print()" <<endl;}    };    void print(A a)    {        a.print();    }    void main()    {        A a,*aa,*ab,*ac;        B b;        C c;        aa=&a;        ab=&b;        ac=&c;        a.print();        b.print();        c.print();        aa->print();        ab->print();        ac->print();        print(a);        print(b);        print(c);    }  



纯虚函数的例子可以参考下面这个大牛的博客:http://blog.csdn.net/hackbuteer1/article/details/7558868。有问题欢迎讨论,后序待补充

0 0
原创粉丝点击