彻底搞懂C++多态虚函数等问题
来源:互联网 发布:淘宝哪家包包好看 编辑:程序博客网 时间:2024/06/06 07:32
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 created
Demo is created
Demo 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 created
Demo is created
Base 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 created
Demo is created
Demo 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 created
Demo is created
Base function is called
Demo 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 created
Demo is created
Demo destroyed!
Base destroyed!
子类对象构造时,会先调用父类的构造函数,然后调用子类的构造函数,初始化子类的特有部分。析构时,顺序相反,先调用子类的析构函数,再调用父类的析构函数。
构造函数和析构函数中都是默认调用父类的函数的。不用像上面那样要额外加上调用父类函数的句子。
有个一直纠结的地方,就是virtual放的位置:virtual应该放在类型前面。比如
virtual int func();
- 彻底搞懂C++多态虚函数等问题
- 嗯,让我们彻底搞懂C/C++函数指针吧
- 《彻底搞懂C指针》
- 彻底搞懂python函数传值or引用问题
- 彻底搞懂jQuery.stop()函数
- 彻底搞懂C语言指针
- 嗯,让我们彻底搞懂C/C++函数指针吧(一)
- 嗯,让我们彻底搞懂C/C++函数指针吧(一)
- 嗯,让我们彻底搞懂C/C++函数指针吧(一)
- 让我们彻底搞懂C/C++函数指针吧(一)
- 让我们彻底搞懂C/C++函数指针吧(二)
- 让我们彻底搞懂C/C++函数指针吧(三)
- 让我们彻底搞懂C/C++函数指针吧(二)
- 让我们彻底搞懂C/C++函数指针吧(三)
- 【转】嗯,让我们彻底搞懂C/C++函数指针吧
- 彻底搞懂 RxJava
- 彻底搞懂CoordinatorLayout
- 彻底搞懂CNN
- 那么URI和URL有什么区别呢?
- C++中 public,protected, private 访问权限标号小结
- 无题 hdu-1871
- 隐式类类型转换
- 无模式对话框
- 彻底搞懂C++多态虚函数等问题
- 每周一计-自己动手做的电源
- 克鲁斯卡尔算法 hdu 1863
- MFC 菜单栏的使用
- 对jsp的一个小结(7)EL表达式(不会报错)和JSTL标签库、sp与jdbc总结
- how to use autologger in reboot trace
- 技术blog02 by 八戒
- 判断AngularJS渲染页面完成
- cocos2d-x-3.4 无法打开包含文件extensions/ExtensionExport.h