C++学习(一)-虚函数(1)

来源:互联网 发布:光盘盘面打印软件 编辑:程序博客网 时间:2024/05/21 06:18

1,多态性:是指不同对象收到相同的信息,产生不同的动作;简单地说,用一个名字定义不同的函数,这些函数执行不同但又类似的动作。也就是“一个接口,多钟方法”。

2,多态分为:编译时的多态和运行时的多态两种。

3,连编:是把函数名和函数体的程序代码连接在一起的过程。静态连编是在编译时完成的,动态连编是在运行时完成的,也就是在发生调用时,才去寻找和连接程序代码。

4,C++是编译性的,仍采用静态编译,但可以通过虚函数机制实现动态连编。编译时的多态性通过函数重载和运算符重载来实现。

5,(1)当基类指针指向子类对象时,基类指针调用基类和子类相同的函数时,调用的是基类的函数。

#include "stdafx.h"#include "iostream"using namespace std;class Base{  public:  Base(int x,int y)  {  a=x;  b=y;  }   void show()  {  cout<<"调用的是基类函数"<<endl;  cout<<a<<" "<<b<<" "<<endl;  }  private:  int a;  int b;};class Derived:public Base{public:Derived(int x,int y,int z):Base(x,y){c=z;} void show()//和基类相同的函数{      cout<<"调用的是子类函数"<<endl;  cout<<"c="<<c<<endl;}private:int c;};int main(){Derived *pc=new Derived(30,50,40);  Base mc (30,20),*pb;pb=pc;            //基类指针指向子类对象//pc->show();       pb->show();     //基类指针调用基类和子类相同的函数时,调用的是基类的函数return 0;      }

     实验结果如下:

  

   (2) 当基类的函数被设置为虚函数时,调用的子类中的函数。

   

#include "stdafx.h"#include "iostream"using namespace std;class Base{  public:  Base(int x,int y)  {  a=x;  b=y;  }  virtual void show()//设置为虚函数  {  cout<<"调用的是基类函数"<<endl;  cout<<a<<" "<<b<<" "<<endl;  }  private:  int a;  int b;};class Derived:public Base{public:Derived(int x,int y,int z):Base(x,y){c=z;} void show(){      cout<<"调用的是子类函数"<<endl;  cout<<"c="<<c<<endl;}private:int c;};int main(){Derived *pc=new Derived(30,50,40);  Base mc (30,20),*pb;pb=pc;            //基类指针指向子类对象//pc->show();       pb->show();     //基类指针调用基类和子类相同的函数时,调用的是子类的函数return 0;      }

 实验结果如下:


     (3) 当基类的虚函数带有缺省参数时时,调用的是基类中函数,即缺省参数的虚函数是静态绑定的。

#include "stdafx.h"#include "iostream"using namespace std;class Base{  public:  Base(int x,int y)  {  a=x;  b=y;  }  virtual void show(char* value="我是缺省参数")//基类虚函数为缺省参数  {  cout<<"调用的是基类函数"<<endl;  cout<<a<<" "<<b<<" "<<value<<"\n"<<endl;  }  private:  int a;  int b;};class Derived:public Base{public:Derived(int x,int y,int z):Base(x,y){c=z;} void show(){      cout<<"调用的是子类函数"<<endl;  cout<<"c="<<c<<endl;}private:int c;};int main(){Derived *pc=new Derived(30,50,40);  Base mc (30,20),*pb;pb=pc;            //基类指针指向子类对象//pc->show();       pb->show();     //基类指针调用基类和子类相同的函数时,调用的是基类的函数return 0;      }

实验结果如下:


     以上(1),(2),(3),全都是基类对象指针指向子类对象。

     (4),当子类对象指针调用基类和子类相同的函数时,调用的是子类中的函数。

       

#include "stdafx.h"#include "iostream"using namespace std;class Base{  public:  Base(int x,int y)  {  a=x;  b=y;  }  void show()//和子类相同的函数  {  cout<<"调用的是基类函数"<<endl;  cout<<a<<" "<<b<<"\n"<<endl;  }  private:  int a;  int b;};class Derived:public Base{public:Derived(int x,int y,int z):Base(x,y){c=z;} void show()//和基类相同的函数{      cout<<"调用的是子类函数"<<endl;  cout<<"c="<<c<<endl;}private:int c;};int main(){Derived *pc=new Derived(30,50,40);  Base mc (30,20),*pb;//pb=pc;            //基类指针指向子类对象pc->show();         //子类对象指针调用基类和子类相同的函数时,调用的时子类的函数。//pb->show();     return 0;      }

实验结果如下:

 

     (5)  子类可以继承基类的函数,并且在一定继承方式下,可以访问它,也就是说,子类没有基类同名的函数,在一定方式下,可以访问基类函数

 

#include "stdafx.h"#include "iostream"using namespace std;class Base{  public:  Base(int x,int y)  {  a=x;  b=y;  }  void show()  {  cout<<"调用的是基类函数"<<endl;  cout<<a<<" "<<b<<"\n"<<endl;  }  private:  int a;  int b;};class Derived:public Base{public:Derived(int x,int y,int z):Base(x,y){c=z;}private:int c;};int main(){Derived *pc=new Derived(30,50,40);  //子类对象指针Base mc (30,20),*pb;//pb=pc;            //基类指针指向子类对象pc->show();         //子类对象指针调用基类函数//pb->show();     return 0;      }


     实验结果如下:

  

 

     (6),子类对象指针可以指向基类对象,但是必须强制类型转换。此时即使子类对象指针指向基类对象,在调用基类和子类相同函数时,调用的是子类函数。

 

#include "stdafx.h"#include "iostream"using namespace std;class Base{  public:  Base(int x,int y)  {  a=x;  b=y;  }  void show()  {  cout<<"调用的是基类函数"<<endl;  cout<<a<<" "<<b<<"\n"<<endl;  }  private:  int a;  int b;};class Derived:public Base{public:Derived(int x,int y,int z):Base(x,y){c=z;}void show(){cout<<"调用的是子类函数"<<endl;//cout<<c<<"\n"<<endl;}private:int c;};int main(){Derived *pc=new Derived(30,50,40);  //子类对象指针Base mc (30,20),*pb;pc=(Derived*)&mc;            //子类对象指针指向基类对象pc->show();         //子类对象指针调用子类函数//pb->show();     return 0;      }


       实验结果:

  

    (7),当子类指针指向基类对象时,必须强制类型转换,若基类和子类中有相同的函数,并且该函数为虚函数,用子类对象指针访问该函数时,访问的是基类中的函数。

  

#include "stdafx.h"#include "iostream"using namespace std;class Base{  public:  Base(int x,int y)  {  a=x;  b=y;  }  virtual void show()//设置为虚函数  {  cout<<"调用的是基类函数"<<endl;  cout<<a<<" "<<b<<"\n"<<endl;  }  private:  int a;  int b;};class Derived:public Base{public:Derived(int x,int y,int z):Base(x,y){c=z;}void show(){cout<<"调用的是子类函数"<<endl;//cout<<c<<"\n"<<endl;}private:int c;};int main(){Derived *pc=new Derived(30,50,40);  //子类对象指针Base mc (30,20),*pb;pc=(Derived*)&mc;            //子类对象指针指向基类对象pc->show();         //子类对象指针调用基类函数//pb->show();     return 0;      }

     实验结果如下:

 

       总结:对于基类和子类中具有的相同函数,对象指针访问函数的选择,依据于其所属的类型,当该函数为虚函数;对象指针访问函数选择,依据于其指向的对象。

     

7,使用对象指针的目的是为了表达一种动态的性质,即当指针指向不同对象时,执行不同的操作。

8,虚函数的定义是在基类中进行的,当某个函数被定义为虚函数,其在一个或多个派生类中可以被重新定义,但是,其函数原型,包括返回值类型,函数名,形参个数,形参类型及顺序,必须与基类中原型完全相同。这也是与重载函数一个不同的地方。

9,通过定义虚函数机制来实现多态时,派生类必须从它的基类中公有继承

10,只有通过基类指针访问虚函数,才能获得运行时的多态性。

11,一个虚函数无论被公有继承多少次,都保有虚函数的特性。


12,虚函数必须是其所在类的成员函数,不能是友元函数,也不能是静态成员函数,因为虚函数调用必须依靠指定的对象来决定该激活哪一个函数。

13,内联函数不能是虚函数,因为内联函数不能再运行时确定其位置。

14,构造函数不能是虚函数,但是析构函数可以是虚函数,并且通常是虚函数。




0 0