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();