一、前言
原文转载自 https://blog.csdn.net/a345203172/article/details/21697687,为了理解下C++中虚函数 纯虚函数 虚基类的基础知识点。
二、虚函数 纯虚函数 虚基类三者区别
1.虚函数是用于多态中virtual修饰父类函数,确保父类指针调用子类对象时,运行子类函数的。
2.纯虚函数是用来定义接口的,也就是基类中定义一个纯虚函数,基类不用实现,让子类来实现。
3.虚基类是用来在多继承中,如果父类继承自同一个父类,就只实例化一个父类(说的有点绕,就是只实例化一个爷爷的意思)
2.1、虚函数
这个和多态有关,多态的定义不清楚的话到其他地方先了解一下,多态的三个必要条件:1.继承 2.重载 3.父类指针指向子类对象。
看一下程序
第一个是没有使用virtual的,没有使用多态的:
class A
{
public:
void printf(){
cout<<"printf A"<printf();
B *b = new B();
b->printf();
return 0;
}
结果:
printf A
printf B
这是最基本的用法,没有多态,只有继承,下面是使用了多态但是没有引用virtual关键字的情况,多态的作用请参考其他地方的文章:
int main(int argc, const char * argv[])
{
A *a = new B();
a->printf();
return 0;
}
结果:
printf A
因为类的定义都一样,所以就没再写出来了,当父类指针指向子类对象的时候,如果不使用virtual,父类调用方法的时候还是调用了父类自己的方法,没有调用子类重写的方法,所以就没有实现到多态的作用,我们再来在父类中试试加入virtual关键字看看:
class A
{
public:
virtual void printf(){
cout<<"printf A"<printf();
return 0;
}
结果
printf B
virtual是加入到父类中的,子类的代码没改变,main函数还是父类指针指向子类对象,结果终于可以打印到子类重写的方法了,所以证实了虚函数是用于多态中virtual修饰父类该重写的函数,确保父类指针调用子类对象时运行子类函数的。
2.2 、纯虚函数
纯虚函数就像java的接口,使用了纯虚函数的类不能被实例化,定义了纯虚函数的类不用写纯虚函数的实现,由子类实现,下面看代码:
class A
{
public:
virtual void printf() =0;
};
void A::printf()//纯虚函数可以不写实现
{
cout<<"printf A"<printf();
return 0;
}
virtual void printf() = 0;这是虚函数的写法,我在下面写了虚函数的实现 void A::printf(),其实写不写都没关系,写了也起不了作用= 。= 。然后我才main函数中尝试吧纯虚函数的类实例化,结果直接报错,说明纯虚函数是不能实例化的。
int main(int argc, const char * argv[])
{
A *a =newB();//这里使用了多态
a->printf();
return 0;
}
结果:
printf B
把main函数的a指向了子类的对象,结果可以正确打印出子类的方法。由此说明了纯虚函数也是为多态服务的,它的作用是定义一个接口,让子类去实现。
2.3、虚基类
虚基类是c++独有的东西,因为c++中有多继承,也是关键字virtual相关的定义。
先来说说多继承,如果爷爷类(暂把父类的父类暂定为爷爷类= = ),父类继承自爷爷类。如果孙类继承自多个父类(听起来有点怪异),那么如果不使用虚基类,就会实例化多个爷爷类对象(越说越离奇),编译器会报错,说有歧义性。如果父类继承自虚基类,则可以解决多个父类不会实例化多个爷爷的问题,就是只有一个爷爷。
class Grandfather{
public:
int flag;
Grandfather(){
flag = 1;
}
};
class Father1:publicGrandfather{
public:
Father1(){
flag = 2;
}
};
class Father2:publicGrandfather{
public:
Father2(){
flag = 3;
}
};
class Son:public Father1,publicFather2{
};
int main(int argc, const char * argv[])
{
Son *son = new Son();
cout<flag<
如果没有使用虚基类,多个父类继承自同一个爷爷类,就会产生歧义,到底是不是同一个爷爷?如果父类继承虚基类就不同了:
class Grandfather{
public:
int flag;
Grandfather(){
flag = 1;
cout<<"Grandfather flag = "<总的来说,虚函数 ,纯虚函数是为了多态服务,虚基类是为了只实例化一次基类存在的