彻底搞懂C++多态虚函数等问题

1.继承和覆写

子类继承父类,子类可以覆写基类的函数。当然,直接生成一个子类的对象,用子类的指针操作是没有问题的。调用的函数是子类的函数,即覆写后的。

// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>using namespace std;class Base{public:Base(void){cout<<"Base is created"<<endl;}virtual ~Base(void){cout<<"Base destroyed!"<<endl;}void func(){cout<<"Base function is called"<<endl;}};class Demo : public Base{public:Demo(void){cout<<"Demo is created"<<endl;}~Demo(void){cout<<"Demo destroyed!"<<endl;}void func(){cout<<"Demo function is called"<<endl;}};int _tmain(int argc, _TCHAR* argv[]){Demo* demo = new Demo();demo->func();int a;cin>>a;return 0;}

结果:

Base is createdDemo is createdDemo function is called

但是,如果要用父类的指针调用子类的对象呢?还是会调用覆写后的函数吗?

答案是不会。。。

// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>using namespace std;class Base{public:Base(void){cout<<"Base is created"<<endl;}virtual ~Base(void){cout<<"Base destroyed!"<<endl;}void func(){cout<<"Base function is called"<<endl;}};class Demo : public Base{public:Demo(void){cout<<"Demo is created"<<endl;}~Demo(void){cout<<"Demo destroyed!"<<endl;}void func(){cout<<"Demo function is called"<<endl;}};int _tmain(int argc, _TCHAR* argv[]){Base* base = new Demo();base->func();//Demo* demo = new Demo();//demo->func();//delete base;int a;cin>>a;return 0;}

Base is createdDemo is createdBase function is called

那么要肿么办呢?

下面就是多态的方法啦。

2.关于多态

多态实际上就是用基类的指针来操作子类的对象。但是上面覆写了之后,却调用的还是父类的函数。要解决这个问题就要加一个关键字,virtual。

就是这一个关键字就改变了程序运行的结果。

// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>using namespace std;class Base{public:Base(void){cout<<"Base is created"<<endl;}virtual ~Base(void){cout<<"Base destroyed!"<<endl;}void virtual func(){cout<<"Base function is called"<<endl;}};class Demo : public Base{public:Demo(void){cout<<"Demo is created"<<endl;}~Demo(void){cout<<"Demo destroyed!"<<endl;}void func(){cout<<"Demo function is called"<<endl;}};int _tmain(int argc, _TCHAR* argv[]){Base* base = new Demo();base->func();//Demo* demo = new Demo();//demo->func();//delete base;int a;cin>>a;return 0;}在要被覆写的基类函数前面加上virtual关键字就可以使父类指针调用子类对象的重写的函数。

结果:

Base is createdDemo is createdDemo function is called

但是还有一种情况,就是即使覆写了父类的函数,但仍然需要父类的函数的功能,这要肿么办呢?

最开始我的想法是从父类的Ctrl+c 然后Ctrl+v过来。后来一想,这个也忒麻烦了吧,而且不利于代码的维护。还好,有这样一个简单的方法。

在子类覆写的函数中,加上这句

Base::func();

即调用了父类的函数,然后再加上子类特有的功能即可。

// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>using namespace std;class Base{public:Base(void){cout<<"Base is created"<<endl;}virtual ~Base(void){cout<<"Base destroyed!"<<endl;}void virtual func(){cout<<"Base function is called"<<endl;}};class Demo : public Base{public:Demo(void){cout<<"Demo is created"<<endl;}~Demo(void){cout<<"Demo destroyed!"<<endl;}void func(){Base::func();cout<<"Demo function is called"<<endl;}};int _tmain(int argc, _TCHAR* argv[]){Base* base = new Demo();base->func();//Demo* demo = new Demo();//demo->func();//delete base;int a;cin>>a;return 0;}

Base is createdDemo is createdBase function is calledDemo function is called

这样就能既使用子类的特有功能,又调用了父类的功能。

3..虚析构函数

如果是基类,没有定义为虚析构函数的话,用基类指针操作子类,不会调用子类对象的析构函数,会导致只释放了基类部分的资源,而定义在子类部分的资源没被释放,造成内存泄露。// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>using namespace std;class Base{public:Base(void){cout<<"Base is created"<<endl;}virtual ~Base(void){cout<<"Base destroyed!"<<endl;}};class Demo : public Base{public:Demo(void){cout<<"Demo is created"<<endl;}~Demo(void){cout<<"Demo destroyed!"<<endl;}};int _tmain(int argc, _TCHAR* argv[]){Base* base = new Demo();delete base;int a;cin>>a;return 0;}运行结果:

Base is createdDemo is createdDemo destroyed!Base destroyed!

子类对象构造时,会先调用父类的构造函数,,然后调用子类的构造函数,初始化子类的特有部分。析构时,顺序相反,先调用子类的析构函数,再调用父类的析构函数。

构造函数和析构函数中都是默认调用父类的函数的。不用像上面那样要额外加上调用父类函数的句子。

一个人的旅行,反而会更贴近自己的内心,

彻底搞懂C++多态虚函数等问题

相关文章:

你感兴趣的文章:

标签云: