彻底搞懂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 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!
子类对象构造时,会先调用父类的构造函数,然后调用子类的构造函数,初始化子类的特有部分。析构时,顺序相反,先调用子类的析构函数,再调用父类的析构函数。
构造函数和析构函数中都是默认调用父类的函数的。不用像上面那样要额外加上调用父类函数的句子。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。