c++中的 虚函数 纯虚函数 虚基类

匿名 (未验证) 提交于 2019-12-03 00:37:01

一、前言

https://blog.csdn.net/a345203172/article/details/21697687,为了理解下C++中虚函数 纯虚函数 虚基类的基础知识点。

二、虚函数 纯虚函数 虚基类三者区别

2.1、虚函数

1.继承 2.重载 3.父类指针指向子类对象。

看一下程序

第一个是没有使用virtual的,没有使用多态的:

class A   {   public:       void printf(){           cout<<"printf A"<<endl;       }   };   class B : public A   {   public:       void printf(){           cout<<"printf B"<<endl;       }   };   int main(int argc, const char * argv[])   {       A *a = new A();       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"<<endl;       }   };   class B : public A   {   public:       void printf(){           cout<<"printf B"<<endl;       }   };   int main(int argc, const char * argv[])   {       A *a = new B();       a->printf();       return 0;   }  

结果

printf B

纯虚函数就像java的接口,使用了纯虚函数的类不能被实例化,定义了纯虚函数的类不用写纯虚函数的实现,由子类实现,下面看代码:

class A   {   public:       virtual void printf() =0;   };   void A::printf()//纯虚函数可以不写实现   {       cout<<"printf A"<<endl;   }   class B : public A   {   public:       void printf(){           cout<<"printf B"<<endl;       }   };   int main(int argc, const char * argv[])   {       A *a =new A();//编译出错,纯虚函数的类不能实例化       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<<son->flag<<endl;//这里编译错误,没法指定flag是指定那一个,歧义       return 0;   }  
如果没有使用虚基类,多个父类继承自同一个爷爷类,就会产生歧义,到底是不是同一个爷爷?如果父类继承虚基类就不同了:
class Grandfather{   public:       int flag;       Grandfather(){           flag = 1;           cout<<"Grandfather flag = "<<flag <<endl;       }   };   class Father1:virtualpublicGrandfather{   public:       Father1(){           flag = 2;           cout<<"Father1 flag = "<<flag<<endl;       }   };   class Father2:virtualpublicGrandfather{   public:       Father2(){           flag = 3;           cout<<"Father2 flag = "<<flag<<endl;       }   };   class Son:public Father1,publicFather2{   };   int main(int argc, const char * argv[])   {       Son *son = new Son();       cout<<son->flag<<endl;       return 0;   }  
结果:

Grandfather flag = 1

Father1 flag = 2

Father2 flag = 3

3

现在,可以运行了,class Father2:virtual public Grandfather,就是继承虚基类的写法,爷爷对象只有一个,爷爷类的变量也只实例化了一次,那为什么最后打印出来的是3呢?看构造函数的顺序就可以看出来了,现在构造了爷爷类,再构造第一个继承的父类,最后继承第二个继承的父类,因此flag最后保持在第二个父类的修改值里了。

总的来说,虚函数 ,纯虚函数是为了多态服务,虚基类是为了只实例化一次基类存在的

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!