派生类

Effective C++读书笔记(5)

徘徊边缘 提交于 2019-12-07 07:22:49
条款07:为多态基类声明virtual析构函数 Declare destructors virtual inpolymorphic base classes 建立一个 TimeKeeper基类,并为不同的计时方法建立派生类: class TimeKeeper { public: TimeKeeper(); virtual ~TimeKeeper(); ... }; class AtomicClock: public TimeKeeper { ... };//原子钟 class WaterClock: public TimeKeeper { ... };//水钟 class WristWatch: public TimeKeeper { ... };//腕表 TimeKeeper* getTimeKeeper(); //返回一个指针,指向一个TimeKeeper派生类的动态分配对象 TimeKeeper *ptk = getTimeKeeper(); //从TimeKeeper继承体系获得一个动态分配对象 ... //运用它 delete ptk; //释放它,避免资源泄漏 很多客户只是想简单地取得时间而不关心如何计算的细节,所以一个 factoryfunction (工厂函数) ——返回一个指向新建派生类对象的基类指针的函数——可以被用来返回一个指向计时对象的指针

Effective c++学习笔记——条款07:为多态基类声明virtual析构函数

跟風遠走 提交于 2019-12-07 07:22:35
Declare destructors virtual in polymorphic base classes 1、为什么要申明虚函数 C++程序 设计中通常会存在一个基类有多个派生类型,而基类中的存在的大都是纯虚函数,需要派生类型实现。而这样的情况下,通过使用factory模式返回一个基类型的指针。在C++中明确指出,一个派生类型经过由一个基类型指针被删除,而该基类型带着一个non-virtual析构函数其结果未定义。只会造成一个局部的销毁,即基类型资源被释放,而派生类型造成memory leak,看下面的代码: // Virtual_Const.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> using namespace std; class Base{ public: Base(){} ~Base(){ cout<<"~Base()"<<endl;}////不带virtual时输出的结果请看图一 //virtual ~Base(){ cout<<"~Base()"<<endl;}////正确的做法带virtual时输出的结果请看图二 }; class Derived:public Base{ public: Derived() { p=(char*)malloc(sizeof(char)*10)

C++虚析构函数详解

喜夏-厌秋 提交于 2019-12-07 07:18:42
当派生类的对象从内存中撤销时一般先调用派生类的析构函数,然后再调用基类的析构函数。但是,如果用new运算符建立了临时对象,若基类中有析构函数,并且定义了一个指向该基类的指针变量。在程序用带指针参数的delete运算符撤销对象时,会发生一个情况:系统会只执行基类的析构函数,而不执行派生类的析构函数。 [例12.3] 基类中有非虚析构函数时的执行情况。为简化程序,只列出最必要的部分。 #include <iostream> using namespace std; class Point //定义基类Point类 { public: Point( ){} //Point类构造函数 ~Point(){cout<<"executing Point destructor"<<endl;} //Point类析构函数 }; class Circle:public Point //定义派生类Circle类 { public: Circle( ){} //Circle类构造函数 ~Circle( ){cout<<"executing Circle destructor"<<endl;} //Circle类析构函数 private: int radius; }; int main( ) { Point *p=new Circle; //用new开辟动态存储空间 delete p; /

c++ 虚析构函数的作用分析

末鹿安然 提交于 2019-12-07 07:17:55
1.为什么基类的析构函数是虚函数?    在实现多态时,当用基类指针操作派生类对象时,在析构时防止只析构基类而不析构派生类的状况发生。 什么是多态: 根据面向对象的继承规则,派生类跟基类是IS-A的关系。也就是说派生类的对象也是一个基类对象。所以基类的指针可以指向派生类的对象以便实现多态。(让基类实现多态) 亦即: 这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用; 下面看代码----------------------------------------------------------------------------------------------------------   a.第一段代码    #include<iostream> using namespace std; class ClxBase{ public : ClxBase() {}; ~ClxBase() {cout << " Output from the destructor of class ClxBase! " << endl;}; void DoSomething() { cout << " Do something in class ClxBase! " << endl; }; }; class ClxDerived : public ClxBase{

C++——基类的析构函数没有声明为虚函数造成的影响

北城余情 提交于 2019-12-07 07:15:37
C++明确指出,当派生类对象经由一个基类指针被删除,而该基类带着一个non-virtual析构函数(即非虚析构函数),其结果是未有定义的,实际在执行时通常会发生的是对象的派生成分没有被销毁(即派生类的析构函数没有执行),这样就造成基类成分被销毁了,但是派生类成分没有被销毁,于是造成了一个诡异的“局部销毁”对象,这样可能会形成资源泄漏、败坏之数据结构,在调试器上浪费很多时间进行调试。 来源: CSDN 作者: 鬼 | 刀 链接: https://blog.csdn.net/gaoyu1253401563/article/details/90600657

虚析构函数

十年热恋 提交于 2019-12-07 07:10:21
直接的讲,C++中基类采用virtual虚析构函数是为了防止内存泄漏。 具体地说, 如果派生类中申请了内存空间 ,并在其 析构函数中 对这些内存空间进行 释放 。假设 基类 中采用的是 非虚析构函数 ,当delete 基类指针指向的派生类对象时 就不会触发 动态绑定 ,因而 只会调用基类的析构函数 ,而 不会调用派生类的析构函数 。那么在这种情况下, 派生类中申请的空间就得不到释放从而产生内存泄漏 。如果基类中析构函数声明为虚函数,则delete基类指针指向的派生类对象时通过动态绑定能够调用派生类的虚构函数,先执行派生类析构函数的函数体,再执行基类析构函数的函数体。所以,为了防止这种情况的发生,C++中基类的析构函数应采用virtual虚析构函数。 示例 基类析构函数未声明虚函数 #include <iostream> using namespace std; class Base { public: ~Base(){cout<<"~Base()"<<endl;} }; class Derived:public Base { public: virtual ~Derived(){cout<<"~Derived()"<<endl;} }; void test() { Base* b=new Derived(); delete b; cin.get(); } 输出

C++中基类的析构函数为什么用virtual虚析构函数

折月煮酒 提交于 2019-12-07 07:09:38
C++中基类采用virtual虚析构函数是为了防止内存泄露的。 具体来说,如果派生类申请了内存空间,并在其析构函数中对该内存空间进行释放,如果基类采用的非虚析构函数,则删除基类指针指向的派生类对象时,就不会触发动态绑定,因此,只会调用基类的虚构函数,而不会调用该派生类的析构函数。因此,在这种情况下,派生类中申请的空间就得不到释放从而产生内存泄漏。为了防止该情况的发生,C++中基类的析构函数应该采用virtual虚析构函数。 关于动态绑定,简单来说,虚函数是动态绑定的基础,动态绑定是实现运行多态的基础,需要触发动态绑定,需要满足以下两个条件: 只有虚函数才能进行动态绑定,非虚函数不能进行动态绑定。 必须通过基类的引用或指针进行函数的调用。 通过基类指针或基类引用做形参,当实参传入不同的派生类(或基类)的指针或引用,在函数内部触发动态绑定,从而来运行时实现多态的。 示例代码讲解 using namespace std ; class Base { public : ~ Base ( ) { cout << "~Base()" << endl ; } } ; class Derived1 : public Base { public : Derived1 ( ) : name_ ( new string ( "NULL" ) ) { } Derived1 ( const string &

为什么基类中的析构函数要声明为虚析构函数?

為{幸葍}努か 提交于 2019-12-07 07:05:29
题目 为什么基类中的析构函数要声明为虚析构函数? 解答 用对象指针来调用一个函数,有以下两种情况: 如果是虚函数,会调用派生类中的版本。 如果是非虚函数,会调用指针所指类型的实现版本。 析构函数也会遵循以上两种情况,因为析构函数也是函数嘛,不要把它看得太特殊。 当对象出了作用域或是我们删除对象指针,析构函数就会被调用。 当派生类对象出了作用域,派生类的析构函数会先调用,然后再调用它父类的析构函数, 这样能保证分配给对象的内存得到正确释放。 但是,如果我们删除一个指向派生类对象的基类指针,而基类析构函数又是非虚的话, 那么就会先调用基类的析构函数(上面第2种情况),派生类的析构函数得不到调用。 请看例子: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Base { public : Base ( ) { cout << "Base Constructor" << endl ; } ~ Base ( ) { cout << "Base Destructor" << endl ; } } ; class Derived : public Base { public : Derived ( ) { cout << "Derived Constructor" << endl ; } ~ Derived ( ) { cout << "Derived

析构函数是否必须为虚函数?什么情况下才应该定义析构函数为虚函数?

佐手、 提交于 2019-12-07 06:59:32
多态是面向对象的一个基本属性,包括静态多态(编译阶段)和动态多态(运行阶段),静态多态主要是指函数参数不同产生的多态性,是在编译阶段可以识别的一种多态机制,而运行时多态则主要用于基类指针指向派生类对象时,可以通过基类指针直接调用派生类的对象函数,当然这种多态是通过虚函数实现的。 虚函数的目的就是通知系统在函数调用时能够自动识别对应的类对象类型,从而能够根据指针所指类型调用对应的类对象,实现函数调用时的多态性。对于析构函数而言,同样适用于上述规则。如果析构函数不是虚函数,那么在调用该函数时(对象被删除时)则只会调用当前对象对应的类的析构函数,这对于直接定义的对象是没有什么影响的,但是对于使用基类指向派生类的指针而言,因为基类指针实际上是基类类型,所以析构时自然只会调用基类的析构函数,这就可能产生内存泄漏(因为派生类的析构函数不被调用)。所以如果确定程序中有基类指针指向派生类的问题,则必须将基类的析构函数指定为虚函数,如此才能确保NEW出来的对象被正确的DELETE。 以下是几个示例程序,用于方便理解: class ClxBase{ public: ClxBase() {}; ~ClxBase() {cout << "Output from the destructor of class ClxBase!" << endl;}; void DoSomething() { cout <<

C++中的虚函数(virtual function)

╄→гoц情女王★ 提交于 2019-12-07 06:56:26
1.简介 虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。假设我们有下面的类层次: class A { public: virtual void foo() { cout << "A::foo() is called" << endl;} }; class B: public A { public: virtual void foo() { cout << "B::foo() is called" << endl;} }; 那么,在使用的时候,我们可以: A * a = new B(); a->foo(); // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的! 这个例子是虚函数的一个典型应用,通过这个例子,也许你就对虚函数有了一些概念。它虚就虚在所谓“推迟联编”或者“动态联编”上,一个类函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的。由于编写代码的时候并不能确定被调用的是基类的函数还是哪个派生类的函数,所以被成为“虚”函数。 虚函数只能借助于指针或者引用来达到多态的效果,如果是下面这样的代码,则虽然是虚函数,但它不是多态的: class A { public: virtual void foo(); }; class B: public A { virtual void foo(); };