为什么构造函数不可以被声明为虚函数而析构函数有时候必须声明为虚函数

一、为什么构造函数不可以被声明为虚函数

1.构造一个对象时必须知道一个对象的实际类型,而虚函数行为1是在运行期间才确定其实际类型的,而构造对象时对象还未构造成功编译器无法知道对象的实际类型。

2.虚函数的执行依赖于虚函数表,而虚函数表是在构造函数中被初始化的,即让vptr指向正确的虚函数表,若将构造函数声明为虚函数,在构造对象期间虚函数表还没有被初始化,将无法进行。

虚函数:C++中的虚函数就是用来解决多态问题的,所谓虚函数就是在基类中声明函数是虚拟的,并不是实际存在的函数,然后再派生类中才正式定义此函数。

二、为什么析构函数有时候必须声明为虚函数

1.一般情况下:

#define  _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stdlib.h>
using namespace std;
class Base
{
public:
Base(char *pStr = '\0')
{
if(NULL == pStr)
{
_pStr = new char[1];
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr)+1];
strcpy(_pStr,pStr);
}
cout<<"Base()"<<endl;
}
~Base()
{
if(NULL != _pStr)
{
delete[]_pStr;
_pStr = NULL;
}
cout<<"~Base()"<<endl;
}
private:
char * _pStr;
};
class Derived:public Base
{
public:
Derived(char *dStr = '\0')
{
if(NULL == dStr)
{
_dStr = new char[1];
*_dStr = '\0';
}
else
{
_dStr = new char[strlen(dStr)+1];
strcpy(_dStr,dStr);


}
cout<<"Derived()"<<endl;
}
~Derived()
{
if(NULL != _dStr)
{
delete[]_dStr;
_dStr = NULL;
}
cout<<"~Derived()"<<endl;
}
private:
char *_dStr;
};
void FunTest()
{
Derived *p = new Derived;//采用派生类指针或者引用操作派生类
delete p;
}
int main()
{
FunTest();
system("pause");
return 0;
}


这种情况下析构函数不是虚函数,在main函数中采用派生类的指针去操作派生类,是释放指针的过程是先释放派生类的资源再释放基类的资源。

2.第一种情况:

#define  _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stdlib.h>
using namespace std;
class Base
{
public:
Base(char *pStr = '\0')
{
if(NULL == pStr)
{
_pStr = new char[1];
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr)+1];
strcpy(_pStr,pStr);
}
cout<<"Base()"<<endl;
}
~Base()
{
if(NULL != _pStr)
{
delete[]_pStr;
_pStr = NULL;
}
cout<<"~Base()"<<endl;
}
private:
char * _pStr;
};
class Derived:public Base
{
public:
Derived(char *dStr = '\0')
{
if(NULL == dStr)
{
_dStr = new char[1];
*_dStr = '\0';
}
else
{
_dStr = new char[strlen(dStr)+1];
strcpy(_dStr,dStr);


}
cout<<"Derived()"<<endl;
}
~Derived()
{
if(NULL != _dStr)
{
delete[]_dStr;
_dStr = NULL;
}
cout<<"~Derived()"<<endl;
}
private:
char *_dStr;
};
void FunTest()
{
Base *p = new Derived;//采用基类指针或者引用操作派生类
delete p;
}
int main()
{
FunTest();
system("pause");
return 0;
}


这种情况下析构函数不是虚函数,在main函数中采用基类的指针去操作派生类,由结果可以看出只调用了基类的析构函数释放了基类 开辟的空间,没有调用派生类的析构函数释放派生类开辟的空间,造成了空间泄露。

在公有继承下,基类只能操作派生类中从基类继承下来的成员,如果想要对派生类中非继承成员进行操作,则成员函数在基类中应该声明为虚函数,为了解决这种基类指针或引用对派生类操作时造成空间泄露的问题应该将析构函数声明为虚函数。

第二种情况

#define  _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stdlib.h>
using namespace std;
class Base
{
public:
Base(char *pStr = '\0')
{
if(NULL == pStr)
{
_pStr = new char[1];
*_pStr = '\0';
}
else
{
_pStr = new char[strlen(pStr)+1];
strcpy(_pStr,pStr);
}
cout<<"Base()"<<endl;
}
virtual ~Base()//基类析构函数声明为虚函数
{
if(NULL != _pStr)
{
delete[]_pStr;
_pStr = NULL;
}
cout<<"~Base()"<<endl;
}
private:
char * _pStr;
};
class Derived:public Base
{
public:
Derived(char *dStr = '\0')
{
if(NULL == dStr)
{
_dStr = new char[1];
*_dStr = '\0';
}
else
{
_dStr = new char[strlen(dStr)+1];
strcpy(_dStr,dStr);


}
cout<<"Derived()"<<endl;
}
~Derived()
{
if(NULL != _dStr)
{
delete[]_dStr;
_dStr = NULL;
}
cout<<"~Derived()"<<endl;
}
private:
char *_dStr;
};
void FunTest()
{
Base *p = new Derived;//采用基类对象或指针操作派生类
delete p;
}
int main()
{
FunTest();
system("pause");
return 0;
}


这种情况基类的析构函数是虚函数,采用基类指针或者引用操作派生类时,释放时先释放调用派生类的析构函数释放空间,再调用基类的析构函数释放空间。

3.一般在不需要基类对象或引用对派生类进行操作时不用将析构函数声明为虚函数,因为类里面定义虚函数时编译器会给类添加一个虚函数表,里面存放虚函数指针,这样就会增加类的存储空间,增加内存开销。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值