一个函数的返回值为基类指针,而当指针指向一个派生类对象,接下来派生类对象被这个基类指针删除的时候,就出现了局部销毁的问题.因为C++指出,当派生类经由一个基类指针被删除,而该基类指针带着一个non-virtual析构函数,其结果未有定义.实际的执行情况是派生类的析构函数没有执行,然而基类的成分通常会被销毁,于是早晨了诡异的"局部销毁"对象.这是造成资源泄漏.败坏数据结构.在调试器上浪费许多时间的绝佳途径==. 给基类一个virtual析构函数就可以消除这个问题了. 如果基类不含virt…
C++明确指出:当派生类对象是由一个基类指针释放的,而基类中的析构函数不是虚函数,那么结果是未定义的.其实我们执行时其结果就是:只调用最上层基类的析构函数,派生类及其中间基类的析构函数得不到调用. #include <iostream> using namespace std; class TimeKeeper { public: TimeKeeper(); ~TimeKeeper(); }; TimeKeeper::TimeKeeper() { cout << "Con…
引言: 我们都知道类的一个很明显的特性是多态,比如我们声明一个水果的基类: class Fruit { public: Fruit() {}; ~Fruit(){}; } 那么我们根据这个Fruit基类可以派生出以下的子类: class Apple:public Fruit{}; class Orange:public Fruit{}; 那么问题来了,如果我们想经由一个基类指针去删除一个派生类Apple,且我们有以下的方法 Fruit * foo(){ Apple * p = new Apple…
class TimeKeeper { public: TimeKeeper() ; ~TimeKepper() ; ... } ; class AtomicClock:public TimeKeeper{...}// 原子钟 class WaterClock:public TimeKeeper{...}// 水钟 class WristWatch:public TimeKeeper{...}// 腕表 根据工厂模式,会返回一个base class指针指向新生成的derived class对象.…
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 这个规则只适用于polymorphic(带多态性质的)base class身上.这种base class的设计目的是为了用来“通过base class接口处理derived class对象”.假如我们在程序中设计factory(工厂)函数,让它返回base class指针,指向新生成的derived class对象,假设base class有个non-virtu…
来自<Effective C++>条款07:为多态声明virtual析构函数 当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未有定义——实际执行时通常发生的是对象的derived成分没被销毁,而其基类成分通常会被销毁,于是造成了一个诡异的“局部销毁”对象. 解决这个问题的做法很简单:给base class一个virtual析构函数.此后删除derived class对象就会如你想要的那般销毁整个对象…
注意:polymorphic base class 应该具有虚析构函数,如果class带有任何virtual函数,也应具有虚析构函数 class不具备polymorphic属性则不应该声明virtual 析构函数 1.老生常谈,如果一个类需要被使用为base calss 则为它声明 "virtual析构函数",确保删除一个"指向派生类对象的基类指针" 时内存完整删除 2.对于不需要使用为base class的类,反而不声明virtual 函数是最好的,如果你的类只具…
问题聚焦: 已经对一个对象执行了delete语句,还会发生内存泄漏吗? 先来看个demo: // 计时器类 class TimeKeeper { public: TimeKeeper(); ~TimeKeeper(); }; class AtomicClock: public TimeKeeper { ...... }; // 原子钟 class WaterClock: public TimeKeeper { ...... }; // 水表 class WristWatch: public Ti…
polymorphic(带多态性质的)base classes应该声明一个virtual析构函数.如果class带有任何virtual函数,它就应该拥有一个virtual析构函数. Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性(polymorphically),就不该声明virtual析构函数.…
一.C++明确指出:当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未定义——实际执行时通常发生的是对象的derived成分没有被销毁!(注:使用基类引用派生类的方式使用多态,由于引用只是对原对象的一个引用或者叫做别名,其并没有分配内存,对其引用对象内存的销毁,将由原对象自己负责,所以使用引用的时候,如果析构函数不为virtual,那么也不会发生derived成员没有销毁的情况) 例如: class b…
class TimeKeeper { public: TimeKeeper(); // ~TimeKeeper(); 错误,此作为一个基类,被继承了.其继承类被delete后,基类被销毁,但继承类可能没被销毁 virtual ~TimeKeeper();//必须声明为virtual类型才可以. protected: private: };   class AtomicClock: public TimeKeeper{}; //继承   TimeKeeper* ptk = getTimeKeepe…
在继承中,基类的析构函数需要定义为虚析构函数数否则: (1)当派生类对象经由一个base类指针删除时,而这个base类的析构函数不是虚函数时,其结果是未定义的. (2)这样做会导致derived类部分的成员没有被销毁,即造成局部销毁的对象. (3)从而造成资源泄漏,败坏之数据结构,在调试器上浪费去多时间. 记住: (1)带多态性质的base class 应该声明一个virtual析构函数,如果base class带有任何的虚函数,那么应该声明虚析构函数. (2)一般析构函数的调用是.最深层次的析…
Declare destructors virtual in polymorphic base classes.   [原理] C++指出,当derived class对象经由一个由base class类型的指针删除时,如果这个base class 拥有一个non-virtual的析构函数,那个析构的结果将是未定义的.即通常情况下是该对象的base class成分会被析构掉,但是其derived class成分没有被销毁,甚至连derived class的析构函数也不会被调用. 于是形成一个被“…
7.为多态基类声明虚析构函数 1.为多态基类声明虚析构函数 code1: class A{ public: int* a; A():a(new int(5)) {} ~A(){ delete a; } }; class B:public A { public: int *b; B():b(new int(10)) {} ~B(){ delete b; } }; int main(int argc, char const *argv[]) { B *bb=new B; A* aa=bb; dele…
NOTE: 1.polymorphic(多态性质的)base classes 应该声明一个virtual 析构函数.如果class带有任何virtual函数,它就应该拥有一个virtual析构函数. 2.Classes 的设计目的如何不是作为bases classes 使用,或不是为了具备多态性(polymorphically),就不该声明为virtual 析构函数.…
1.考虑下面的需要,需要一个工厂方法.工厂方法的规则是:在堆上分配一个子类对象,并返回父类指针.使用完毕,delete父类指针.如果父类的析构方法不是virtual,将直接调用父类的析构方法,导致局部销毁的对象,父类成分销毁了,子类成分没有销毁. 2.如果类中有virtual方法,意味着面向抽象编程,也就是会有父类指针指向子类对象,因此这种情况下,必定需要一个virtual析构方法. 3.如果类中没有virtual方法,为了节省空间,析构方法是non-virtual方法.也就意味着,这个类不作为…
当基类确定被继承的时候,析构函数声明为virtual是必须的 当返回的派生类的指针或引用的时候,调用析构函数容易发生内存泄漏 当基类作为抽象类使用,声明pure virtual析构函数 析构函数的顺序————派生类的析构函数先被调用(先析构基类成员) 构造函数的顺序————派生类的构造函数先被调用(先构造基类成员)…
主要内容: 1.C++类继承中的构造函数和析构函数 2.C++多态性中的静态绑定和动态绑定 3.C++多态性中析构函数声明为虚函数 1.C++类继承中的构造函数和析构函数 在C++的类继承中, 建立对象时,首先调用基类的构造函数,然后在调用下一个派生类的构造函数,依次类推: 析构对象时,其顺序正好与构造相反: 具体参考文章:http://www.cnblogs.com/AndyJee/p/4575385.html 2.C++多态性中的静态绑定和动态绑定 对象的静态类型:对象在声明是采用的类型,在…
1. 继承体系中关于对象释放遇到的问题描述 1.1 手动释放 关于时间记录有很多种方法,因此为不同的计时方法创建一个TimeKeeper基类和一些派生类就再合理不过了: class TimeKeeper { public: TimeKeeper(); ~TimeKeeper(); ... }; class AtomicClock: public TimeKeeper { ... }; class WaterClock: public TimeKeeper { ... }; class Wrist…
基类声明的指针变量和引用类型变量可以指向派生类的对象,而反过来派生类的指针却不能指向基类变量. 这与基类和派生类之间,被允许的赋值方向是相反的. 但是从逻辑上很容易推敲其合理性.…
基类指针指向子类对象. 子类对象必须位于堆.因此为了避免泄漏内存资源,当指针不使用时,delete掉每一个对象非常重要.但是如果基类的析构函数不声明为virtual.那么指向子类对象的指针delete时,析构掉的成分都是基类的,而子类的成分没有被识别出来,而未被析构掉.这样就造成资源浪费.给基类析构函数声明为virtual,那么delete对象时,就会是你希望的那样,它会销毁整个对象,包括所有继承类(drived class)的成分.析构时调用顺序:先调用最深层次的派生类的析构函数,依次向上调用…
#include <iostream> using namespace std; class Father { public: ~Father() { cout << "Father's Desconstruct Called. " << endl; } }; class Son: public Father { public: ~Son() { cout << "Son's Desconstruct Called "…
五条基本规则: 1.如果基类已经插入了vptr, 则派生类将继承和重用该vptr.vptr(一般在对象内存模型的顶部)必须随着对象类型的变化而不断地改变它的指向,以保证其值和当前对象的实际类型是一致的. 2.在遇到通过基类指针或引用调用虚函数的语句时,首先根据指针或引用的静态类型来判断所调函数是否属于该class或者它的某个public 基类,如果 属于再进行调用语句的改写:  C++ Code  1   (*(p->_vptr[slotNum]))(p, arg-list); 其中p是基类指针…
知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定. 关于动态绑定的讲解,请参阅:  C++中的动态类型与动态绑定.虚函数.多态实现 正题 直接的讲,C++中基类采用virtual虚析构函数是为了防止内存泄漏.具体地说,如果派生类中申请了内存空间,并在其析构函数中对这些内存空间进行释放.假设基类中采用的是非虚析构函数,当删除基类指针指向的派生类对象时就不会触发动态绑定,因而只会调用基类的析构函数,而不会调用派生类的析构函数.那么在这种情况下,派生类中申请的空间就得不到释放从而产生内存泄漏…
虚函数作用:动态绑定,实现多态效果. 场景问题: 派生类中有资源需要回收,而在编程中采用多态,由基类的指针指向派生类,则在释放的时候,如果基类的析构函数不是virtual,则派生类的析构函数得不到释放 总结: C++中基类采用virtual虚析构函数是为了防止内存泄漏.具体地说,如果派生类中申请了内存空间,并在其析构函数中对这些内存空间进行释放.假设基类中采用的是非虚析构函数,当删除基类指针指向的派生类对象时就不会触发动态绑定,因而只会调用基类的析构函数,而不会调用派生类的析构函数.那么在这种情…
知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定. 关于动态绑定的讲解,请参阅:  C++中的动态类型与动态绑定.虚函数.多态实现 正题 直接的讲,C++中基类采用virtual虚析构函数是为了防止内存泄漏.具体地说,如果派生类中申请了内存空间,并在其析构函数中对这些内存空间进行释放.假设基类中采用的是非虚析构函数,当删除基类指针指向的派生类对象时就不会触发动态绑定,因而只会调用基类的析构函数,而不会调用派生类的析构函数.那么在这种情况下,派生类中申请的空间就得不到释放从而产生内存泄漏…
正面回答: 当基类的析构函数不是虚函数,并且基类指针指向一个派生类对象,然后通过基类指针来删除这个派生类对象时,如果基类的析构函数不是虚析构函数,那么派生类的析构函数就不会被调用,从而产生内存泄漏 #include<iostream> #include<bits/stdc++.h> using namespace std; class A { public: A() { cout<<"constructing A"<<endl; } ~A…
静态多态.动态多态 静态多态:程序在编译阶段就可以确定调用哪个函数.这种情况叫做静态多态.比如重载,编译器根据传递给函数的参数和函数名决定具体要使用哪一个函数.动态多态:在运行期间才可以确定最终调用的函数.需要通过虚函数+封装+继承实现. 虚函数 虚函数都必须有定义 虚函数一般用在继承中.多个子类继承同一基类,若在某种行为上不同的派生类有着自己的实现方式.这种情况我们就会用到多态.采用在基类中将此函数定义成虚函数,派生类中定义这个函数的不同实现.当我们使用基类的引用或指针调用一个虚成员函数时会执…
虚析构函数的理论前提是 执行完子类的析构函数,那么父类的虚构函数必然会被执行. 那么当用delete释放一个父类指针所实例化的子类对象时,如果没有定义虚析构函数,那么将只会调用父类的析构函数,而不会调用子类的虚构函数,导致内存的泄漏. 故: 继承时,要养成的一个好习惯就是,基类析构函数中,加上virtual. 知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定. 关于动态绑定的讲解,请参阅:  C++中的动态类型与动态绑定.虚函数.多态实现 正题 直接的讲,C++中基类采用virtual…
一.基类指针.派生类指针 父类指针可以new一个子类对象 二.虚函数 有没有一个解决方法,使我们只定义一个对象指针,就可以调用父类,以及各个子类的同名函数? 有解决方案,这个对象指针必须是一个父类类型,我们如果想通过一个父类指针调用父类.子类中的同名函数的话,这个函数是有要求的: 在父类中,eat函数声明之前必须要加virtual声明eat()函数为虚函数. 一旦某个函数被声明为虚函数,那么所有派生类(子类)中eat()函数都是虚函数. 为了避免你在子类中写错虚函数,在C++11中,你可以在函数…