多态时最好将基类的析构函数设为virtual
2012-11-04 20:01
295 查看
多态时最好将基类的析构函数设为virtual,这样在析构时会先调用子类的析构函数,再调用基类的析构函数,否则如果delete的是基类的指针,则只调用基类的析构函数.示例如下:
#include <iostream.h>
class Base
{
public:
Base() { mPtr = new int; }
virtual ~Base() { delete mPtr; cout<<"~Base::Base()"<<endl;}
private:
int* mPtr;
} ;
class Derived : public Base
{
public:
Derived() { mDerived = new long; }
~Derived() { delete mDerived; cout<<"~Derived::Derived()"<<endl;}
private:
long* mDerived;
} ;
void main()
{
Base* p = new Derived;
delete p;
}
结果:
先调用子类的析构函数:释放mDerived,输出"~Derived::Derived()";
再调用父类的析构函数:释放mPtr,输出"~Base::Base()"。
------------
#include <iostream.h>
class Base
{
public:
Base() { mPtr = new int; }
~Base() { delete mPtr; cout<<"~Base::Base()"<<endl;}
private:
int* mPtr;
} ;
class Derived : public Base
{
public:
Derived() { mDerived = new long; }
~Derived() { delete mDerived; cout<<"~Derived::Derived()"<<endl;}
private:
long* mDerived;
} ;
void main()
{
Base* p = new Derived;
delete p;
}
结果:只调用了父类的析构函数:释放mPtr,输出"~Base::Base()"。
以上代码会产生内存泄露,因为new出来的是Derived类资源,采用一个基类的指针来接收,析构的时候,编译器因为只是知道这个指针是基类的,所以只将基类部分的内存析构了,而不会析构子类的,就造成了内存泄露,如果将基类的析构函数改成虚函数,就可以避免这种情况,因为虚函数是后绑定,其实就是在虚函数列表中,析构函数将基类的析构函数用实际对象的一组析构函数替换掉了,也就是先执行子类的虚函数再执行父类的虚函数,这样子类的内存析构了,父类的内存也释放了,就不会产生内存泄露。
上面代码中,如~Base()不是virtual,而~Derived()为virtual,则
Base* p = new Derived; delete p;
仍然只调用~Base::Base(),因为delete p中的p是Base*类型,而Base的析构函数~Base()不是virtual。
另:delete子类指针时,会调用子类的析构函数,然后自动调用其父类的析构函数(不管~Derived::Derived()是否为virtual,~Derived::Derived()内部总会自动调用~Base::Base()),如:
Derived * pd = new Derived;
delete pd;//调用 ~Derived::Derived(),并自动析构父类(调用~Base::Base())
注:
1.析构函数其实是一个函数,不论子类还是父类,虽然可能看起来名字不一样。而且析构函数执行过程都是执行子类再到父类。
2.多态的时候一定要将析构函数写成虚函数,防止内存泄露,各个子类维护自己内部数据释放。
virtual 是实现多态的基础
它使得具体的函数跳转从编译时推迟到运行时然而构造函数的调用是编译器期间就决定的,因此它不能为虚.
#include <iostream.h>
class Base
{
public:
Base() { mPtr = new int; }
virtual ~Base() { delete mPtr; cout<<"~Base::Base()"<<endl;}
private:
int* mPtr;
} ;
class Derived : public Base
{
public:
Derived() { mDerived = new long; }
~Derived() { delete mDerived; cout<<"~Derived::Derived()"<<endl;}
private:
long* mDerived;
} ;
void main()
{
Base* p = new Derived;
delete p;
}
结果:
先调用子类的析构函数:释放mDerived,输出"~Derived::Derived()";
再调用父类的析构函数:释放mPtr,输出"~Base::Base()"。
------------
#include <iostream.h>
class Base
{
public:
Base() { mPtr = new int; }
~Base() { delete mPtr; cout<<"~Base::Base()"<<endl;}
private:
int* mPtr;
} ;
class Derived : public Base
{
public:
Derived() { mDerived = new long; }
~Derived() { delete mDerived; cout<<"~Derived::Derived()"<<endl;}
private:
long* mDerived;
} ;
void main()
{
Base* p = new Derived;
delete p;
}
结果:只调用了父类的析构函数:释放mPtr,输出"~Base::Base()"。
以上代码会产生内存泄露,因为new出来的是Derived类资源,采用一个基类的指针来接收,析构的时候,编译器因为只是知道这个指针是基类的,所以只将基类部分的内存析构了,而不会析构子类的,就造成了内存泄露,如果将基类的析构函数改成虚函数,就可以避免这种情况,因为虚函数是后绑定,其实就是在虚函数列表中,析构函数将基类的析构函数用实际对象的一组析构函数替换掉了,也就是先执行子类的虚函数再执行父类的虚函数,这样子类的内存析构了,父类的内存也释放了,就不会产生内存泄露。
上面代码中,如~Base()不是virtual,而~Derived()为virtual,则
Base* p = new Derived; delete p;
仍然只调用~Base::Base(),因为delete p中的p是Base*类型,而Base的析构函数~Base()不是virtual。
另:delete子类指针时,会调用子类的析构函数,然后自动调用其父类的析构函数(不管~Derived::Derived()是否为virtual,~Derived::Derived()内部总会自动调用~Base::Base()),如:
Derived * pd = new Derived;
delete pd;//调用 ~Derived::Derived(),并自动析构父类(调用~Base::Base())
注:
1.析构函数其实是一个函数,不论子类还是父类,虽然可能看起来名字不一样。而且析构函数执行过程都是执行子类再到父类。
2.多态的时候一定要将析构函数写成虚函数,防止内存泄露,各个子类维护自己内部数据释放。
virtual 是实现多态的基础
它使得具体的函数跳转从编译时推迟到运行时然而构造函数的调用是编译器期间就决定的,因此它不能为虚.
相关文章推荐
- 多态时最好将基类的析构函数设为virtual、 C++中两个类相互包含引用问题 (转载)
- [翻译] Effective C++, 3rd Edition, Item 7: 在 polymorphic base classes(多态基类)中将 destructors(析构函数)声明为 virtual(虚拟)
- 多态基类的析构函数必须加上virtual
- 必须为多态基类声明 virtual 析构函数
- Effective C++ 条款07 为多态基类声明virtual 析构函数
- 关于多态基类的析构函数声明为virtual
- Effective C++笔记之四 多态基类申明为virtual 析构函数
- 多态基类的析构函数请加上virtual
- effect C++ 为多态基类声明virtual 析构函数
- C++将多态基类的析构函数声明为virtual的作用
- c++之Item7在多态基类中将析构函数声明为virtual
- Effective C++ 条款07 为多态基类声明virtual 析构函数
- 当使用多态时,请为基类声明 virtual 析构函数
- 基类的析构函数声明为virtual比较安全
- C/C++沉思-----多态时一定要将父类(基类)的析构函数定义为虚函数
- C#基础:多态:基类可以定义并实现虚(virtual)方法,派生类可以重写(override)这些方法
- (C++)浅谈多态基类析构函数声明为虚函数
- [C++基础]023_为什么要将基类的析构函数声明为Virtual?
- 要将多态基类的析构函数声明为虚函数(Effective C++ )
- [转]c++ 为什么要将基类的析构函数声明为Virtual?