您的位置:首页 > 编程语言 > C语言/C++

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

2015-09-30 15:06 453 查看
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,构造函数不能是虚函数,但是析构函数可以是虚函数,并且通常是虚函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: