条款7:为多态基类声明virtual析构函数
2014-05-24 13:17
190 查看
条款7:为多态基类声明virtual析构函数
C++中明确规定:为derived class对象经由base class指针删除时,而该base class指针带有一个non-virtual函数时,其结果未定义--实际执行时通常发生的是derived对象没有被销毁。
TimeKeeper construction
AtomicClock construction
TimeKeeper destruction
新创建一个AtomicClock对象,调用基类构造函数,再调用本类构造函数,然后将地址赋给基类指针,释放基类指针,只是调用基类析构函数,AtomicClock对象没有被析构,里面的动态成员没有被释放内存,导致内存泄露。
消除这种情况,只需要将基类析构函数声明为虚析构函数
TimeKeeper construction
AtomicClock construction
AtomicClock destruction
TimeKeeper destruction
如果一个类不含有虚函数,而且不是当做基类,就为该class声明虚析构函数。类有虚函数会存在代价的
①移植困难
看下面代码
X:4 Y :5
将析构函数改成虚析构函数后
X:3359148 Y :4
看到的结果,X的值是一个指针的地址值(vptr,下面详说), Y是第二个值。
②增大内存开销
一个class存在虚函数,那些编译器为该类生成一个vptr(虚函数指针),占用内存4 byte,vptr主要是指向本类中的虚函数地址列表(vtbl),是一个数组,每个元素存放虚函数地址。vptr在类中空间部署,有些编译器是放在开头,如上面X就是虚函数地址,有些是放在后面。
如果系统中存在很多这样的函数,那会额外占用很大的内存,特别是对一些内存有限制的系统。
抽象类不能够实例化对象,只能通过指针指向derived class对象,实现多态性机制。但抽象类的定义需要有一个pure 虚函数,如果一个abstract class类中没有其他函数当做pure 虚函数,那么令析构函数为pure virtual 函数是一个良好的做法,这样该类既有虚析构函数,又可以将其抽象。
将TimeKeeper类定义为抽象类可如下,注意一点:纯虚析构函数必须定义,因为析构函数的运作方式是:先调用最深层的derived class析构函数,最后调用base class析构函数,如果不定义,则连接器会报错
记住:
1、polymorphic(带多态性质的) base classes应该声明一个virtual 析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual析构函数。
2、Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性质(polymorphically),就不该声明virtual析构函数。
C++中明确规定:为derived class对象经由base class指针删除时,而该base class指针带有一个non-virtual函数时,其结果未定义--实际执行时通常发生的是derived对象没有被销毁。
1、时钟例子
class TimeKeeper { public: TimeKeeper() { cout<<"TimeKeeper construction\n"; } ~TimeKeeper() { cout<<"TimeKeeper destruction\n"; } }; //本例只是说明虚析构函数作用,那些自定义拷贝构造函数、拷贝赋值函数不考虑 class AtomicClock : public TimeKeeper { public: AtomicClock(const char* time) : TimeKeeper() { cout<<"AtomicClock construction\n"; this->m_time = new char[strlen(time) + 1]; strcpy(this->m_time, time); } ~AtomicClock() { cout<<"AtomicClock destruction\n"; if (this->m_time != NULL) delete m_time; m_time = NULL; } private: char *m_time; };调用
TimeKeeper *pTime = new AtomicClock("2014:5:24"); delete pTime; pTime = NULL;结果如下:
TimeKeeper construction
AtomicClock construction
TimeKeeper destruction
新创建一个AtomicClock对象,调用基类构造函数,再调用本类构造函数,然后将地址赋给基类指针,释放基类指针,只是调用基类析构函数,AtomicClock对象没有被析构,里面的动态成员没有被释放内存,导致内存泄露。
消除这种情况,只需要将基类析构函数声明为虚析构函数
virtual ~TimeKeeper() { cout<<"TimeKeeper destruction\n"; }同样调用,结果如下
TimeKeeper construction
AtomicClock construction
AtomicClock destruction
TimeKeeper destruction
2、虚函数指针
一个class被当做base class,那些一般都是可以对derived class动态调用,实现对基类客制化,即同一个函数接口可以由derived class实现不同的行为,这通过虚函数接口实现,class中存在虚函数,那么几乎需要存在一个虚析构函数。如果一个类不含有虚函数,而且不是当做基类,就为该class声明虚析构函数。类有虚函数会存在代价的
①移植困难
看下面代码
class Point { public: Point(const int x, const int y) : m_x(x), m_y(y) { } ~Point() {} private: int m_x; int m_y; };调用,赋给C语言结构体
Point point(4, 5); typedef struct { int x; int y; } Point_C; //c语言结构体 Point_C *pc = (Point_C *)&point; cout<<"X:"<<pc->x<<" Y :"<<pc->y<<endl;调用结果,是我们想得到的
X:4 Y :5
将析构函数改成虚析构函数后
virtual ~Point() {}同样调用结果
X:3359148 Y :4
看到的结果,X的值是一个指针的地址值(vptr,下面详说), Y是第二个值。
②增大内存开销
一个class存在虚函数,那些编译器为该类生成一个vptr(虚函数指针),占用内存4 byte,vptr主要是指向本类中的虚函数地址列表(vtbl),是一个数组,每个元素存放虚函数地址。vptr在类中空间部署,有些编译器是放在开头,如上面X就是虚函数地址,有些是放在后面。
如果系统中存在很多这样的函数,那会额外占用很大的内存,特别是对一些内存有限制的系统。
3、纯虚析构函数
抽象类抽象类不能够实例化对象,只能通过指针指向derived class对象,实现多态性机制。但抽象类的定义需要有一个pure 虚函数,如果一个abstract class类中没有其他函数当做pure 虚函数,那么令析构函数为pure virtual 函数是一个良好的做法,这样该类既有虚析构函数,又可以将其抽象。
将TimeKeeper类定义为抽象类可如下,注意一点:纯虚析构函数必须定义,因为析构函数的运作方式是:先调用最深层的derived class析构函数,最后调用base class析构函数,如果不定义,则连接器会报错
virtual ~TimeKeeper() = 0 { cout<<"TimeKeeper destruction\n"; }并非所有的base类都用来设计成多态性,如实现对象的继承性,后续会详细说明
记住:
1、polymorphic(带多态性质的) base classes应该声明一个virtual 析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual析构函数。
2、Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性质(polymorphically),就不该声明virtual析构函数。
相关文章推荐
- Effective C++——》条款7:为多态基类声明virtual析构函数 .
- (原文)Effective C++条款7:为多态基类声明VIRTUAL析构函数
- 《Effective C++》条款07:为多态基类声明virtual析构函数
- Effective c++(第三版) 条款7:为多态基类声明virtual析构函数
- 《Effective C++读书笔记》--条款07:为多态基类声明virtual析构函数
- 条款:07 为多态基类声明virtual析构函数
- Effective C++_笔记_条款07_为多态基类声明virtual析构函数
- Effective C++ 条款7 为多态基类声明virtual析构函数
- Effective C++ 条款07:为多态基类声明virtual析构函数
- 条款7:为多态基类声明virtual析构函数
- 《Effect C++》学习------条款07:为多态基类声明virtual析构函数
- 条款7:为多态基类声明virtual析构函数
- 读书笔记_Effective_C++_条款七:为多态基类声明virtual析构函数
- Effective c++学习笔记——条款07:为多态基类声明virtual析构函数
- 条款7:为多态基类声明VIRTUAL析构函数
- 条款7:为多态基类声明virtual析构函数
- 读书笔记《Effective C++》条款07:为多态基类声明virtual析构函数
- 条款07:为多态基类声明virtual析构函数
- effective c++条款07为多态基类声明为virtual析构函数
- effective c++ 条款07(为多态基类声明virtual析构函数)整理