精华内容
下载资源
问答
  • 如题。问这问题先基于一个前提条件:析构函数不含释放其他资源代码,甚至可以是空函数,甚至甚至都可以干脆不写。这种情况下是否仍有任何问题。...这样最好情况下,可以做到对于同一个对象,整个
    如题。问这问题时先基于一个前提条件:析构函数不含释放其他资源的代码,甚至可以是空函数,甚至甚至都可以干脆的不写。这种情况下是否仍有任何问题。
      这个问题的结论是 会导致未定义的行为(但不是内存泄漏那么简单)。具体如何就看编译器的实现了。
      我们常用的编译器,如vc、gcc等都是用的尾部追加成员的方式实现的继承(前置基类的实现方式)。这样的话在最好的情况下,可以做到对于同一个对象,整个类 和 其中的基类部分 共享一个内存起始地址(比如单继承且类和其所有基类均无任何虚函数。而这个条件实际上经常无法满足)。也就是说取对象地址,然后转换为void *或者size_t类型再输出,同用基类指针指向这个对象,然后转换指针为void *或者size_t类型再输出,将会发现这两个地址在数值上是相等的。此时如果用delete通过基类指针删除这个对象,可以认为是直接的调用了staitc void operator delete (void *);这个操作符(因为析构函数没做删除其他资源的操作)。所以不会有任何问题。当条件不满足的时候,面临的情况则和下面一种类似。
      另一些编译器(比如适用于某些嵌入式设备的编译器)却使用了先行添加本类成员的方式实现继承(或者说是尾部追加基类视图的方式)。这样即使是单继承也存在类指针数值上的改变(C++标准规定对对象取地址将始终为对应类型的首地址,这样的话如果试图取基类类型的地址,将取到的则是基类部分的首地址。而因为基类被追加到对象末端,所以就会通过在数值上增加地址来跳过派生部分)。此时如果对基类指针做delete操作,会导致很严重的后果。因为编译器从基类指针并不知道派生类是什么,所以删除操作仅能试图删除自己和自己拥有的所有基类部分。但是这个delete所使用的staitc void operator delete (void *);所传入的void*指针并不是原先new所生成的地址。这样将会导致堆内存损坏(不光是内存泄漏了)。
      而如果基类中已经提供了虚析构函数(哪怕只是个空函数)就不会导致错误了,因为通过基类指针调用delete删除派生类对象的时候,delete将通过虚函数定位机制(我这里不说虚表,因为不同的编译器实现不同,有的可能根本没有虚表这种方式)找到整个对象的首地址而不仅仅是基类部分的首地址。注意即使是这种情况下,前面说的问题仍然存在,即通过一个基类指针仍然不可能知道派生类的存在,从而不可能通过形式上的类型推导直接修正指针到最终派生对象的地址。所以这种推导一定发生在运行时(运行时无法推导类型(注意这里不关RTTI的事),而是通过推导逻辑实现)。说的简单些,当一个类的析构函数为虚函数时,通过这种类型的指针删除任一个此类的派生类对象的时候,逻辑上将等同于直接通过最末端派生类的指针删除这个对象(实现的时候多了一个指针重定位动作。但 运行时 开销极小)

      即使在继承树中的各类视图基址不共享的情况下,一般的类型转换(只要你不是将void *指针强制转换成类指针)却并不成问题(但是比前置型多出一定的运行时开销,包括按偏移量移动指针和对NULL地址的特殊处理)。对于p到pBase的隐式指针转换,编译器完全可以偷偷的将地址直接换掉(因为编译器完整的知道源类型和目标类型)。对于将pBase强制转换为p,编译器则通过开发者提供的目标类型获取转换所需的步骤。这种转换和delete删除操作是不一样的,因为仅一句delete pBase中并不包含任何p指向的对象类型的信息。

      始终需要强调的仍然是:不要写出依赖于编译器实现的代码。绝不能依赖于未定义的行为

      最后再说说题外话,为什么有编译器要设计成基类后置型的?因为一些小系统对指针的位宽比较敏感(比如可以参考8086汇编,里面的跳转,不同位宽的偏移量寻址指令速度差异巨大)。让基类视图后置可以做到本类数据成员更靠前从而地址相对于类型基址的偏移量较小,从而加快访问速度。还有些机器的偏移量寻址寄存器的位宽设计本身就比较小,不支持直接跨越较大的地址范围。

    展开全文
  • 2.建立一个对象时,执行构造函数顺序是: a.派生类构造函数先调用基类构造函数; b.再执行派生类构造函数本身(即派生类构造函数函数体) 3.在派生类对象释放时,先执行派生类析构函数,再执行其基类析构函数 ...

    派生类构造函数的一般形式为:

    派生类构造函数名(总参数表):基类构造函数名(参数表)

    {

    派生类中新增加数据成员初始化语句

    }

    2.在建立一个对象时,执行构造函数的顺序是:

    a.派生类构造函数先调用基类构造函数;

    b.再执行派生类构造函数本身(即派生类构造函数的函数体)

    3.在派生类对象释放时,先执行派生类析构函数,再执行其基类析构函数

    展开全文
  • 2.建立一个对象时,执行构造函数顺序是: a.派生类构造函数先调用基类构造函数; b.再执行派生类构造函数本身(即派生类构造函数函数体) 3.在派生类对象释放时,先执行派生类析构函数,再执行其基类析构...

    1.派生类构造函数的一般形式为:

    派生类构造函数名(总参数表):基类构造函数名(参数表)

    {

       派生类中新增加数据成员初始化语句

    }

    2.在建立一个对象时,执行构造函数的顺序是:

    a.派生类构造函数先调用基类构造函数;

    b.再执行派生类构造函数本身(即派生类构造函数的函数体)

    3.在派生类对象释放时,先执行派生类析构函数,再执行其基类析构函数

    转载于:https://www.cnblogs.com/fuqia/p/8854314.html

    展开全文
  • 派生类构造函数定义和使用举例

    万次阅读 2016-05-29 13:43:07
    1.派生类构造函数一般形式为:派生类构造函数名(总参数表):基类构造函数名(参数表...在派生类对象释放时,先执行派生类析构函数,再执行其基类析构函数例:定义一个简单的派生类构造函数。解:程序:#include#inc


    1.派生类构造函数的一般形式为:

    派生类构造函数名(总参数表):基类构造函数名(参数表)

    {

       派生类中新增加数据成员初始化语句

    }

    2.在建立一个对象时,执行构造函数的顺序是:

    a.派生类构造函数先调用基类构造函数;

    b.再执行派生类构造函数本身(即派生类构造函数的函数体)

    3.在派生类对象释放时,先执行派生类析构函数,再执行其基类析构函数

    例:定义一个简单的派生类构造函数。

    解:程序:

    #include<iostream>

    #include<string>

    using namespace std;

    class Student//声明一个基类Student

    {

    public:

    Student(int n, string nam, char s)//定义基类构造函数

    {

    num = n;

    name = nam;

    sex = s;

    }

    ~Student()//基类析构函数

    {

    }

    protected:

    int num; 

    string name;

    char sex;

    };


    class Student1 :public Student//声明公用派生类Student1

    {

    public:

    Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s)//定义派生类构造函数

    {

    age = a;//在函数体中只对派生类新增加的数据成员初始化

    addr = ad;

    }

    void show()

    {

    cout << "num:" << num << endl;

    cout << "name:" << name << endl;

    cout << "sex:" << sex << endl;

    cout << "age:" << age << endl;

    cout << "address:" << addr << endl << endl;

    }

    ~Student1()//派生类析构函数

    {}

    private:

    int age;

    string addr;

    };


    int main()

    {

    Student1 stud1(1001, "yaoyao", 'f', 20, "hanzhong");

    Student1 stud2(1002, "xiaoxiao", 'm', 20, "xianyang");

    stud1.show();//输出第一个学生数据

    stud2.show();//输出第二个学生数据

    system("pause");

    return 0;

    }


    结果:

    num:1001

    name:yaoyao

    sex:f

    age:20

    address:hanzhong

     

    num:1002

    name:xiaoxiao

    sex:m

    age:20

    address:xianyang

     

    请按任意键继续. . .

     


    本文出自 “岩枭” 博客,请务必保留此出处http://yaoyaolx.blog.51cto.com/10732111/1763588

    展开全文
  • 就会调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象完全被释放。 (2)析构函数不定义为虚函数:编译器实施静态绑定,删除基类指针,只会调用基类的析构...
  • 假设基类中采用的是非虚析构函数,当删除基类指针指向的派生类对象时就不会触发动态绑定,因而只会调用基类的析构函数,而不会调用派生类的析构函数。那么这种情况下,派生类中申请的空间就得不到释放从而产生内存...
  • 几个问题 一个类的各数据成员的构造顺序? 按他们类定义中出现的...构造函数和析构函数用来创建和释放类的对象,当这个类是派生类时,其对象的创建和释放应与其基类对象及成员对象相联系。声明派生类时,一...
  • 当初始化派生类的对象时,同时也要初始化基类中的数据成员。 对于派生类中的析构函数也是同​样的道理,同样承担着释放基类中的数据成员。因此,派生类的构造函数和析构函数应该包含它的基类的构造函数和析构函数。...
  • 这样可能导致重大问题是,析构子类对象时可能子类内部对象并未被释放,造成内存泄露。 具体情况上代码分析。 问题代码如下 声明: /**************************************************************** Doc
  • C++创建对象时,会自动调用类的构造函数,构造函数中可以执行初始化数据成员的操作。 析构函数也是一种特殊的成员函数,它执行与构造函数相反的操作,通常完成撤销对象时的一些清理任务,如释放分配给对象的...
  • 析构函数用于销毁对象完成相应资源的释放工作,析构函数可以被声明为虚函数。继承层次中,基类析构函数一般建议声明为虚函数。下面通过一个例子来说明下基类析构函数声明为虚函数必要性。#include using ...
  • C++笔记:面向对象编程(Handle

    千次阅读 2017-09-09 15:14:58
    句柄类 句柄类的出现是为了解决用户使用指针需要控制指针的加载和释放的问题。...句柄类使用指针执行操作,虚成员由于既可以指向基类型又可以指向派生类型,所以其行为将运行根据句柄实际绑定的对象而变化。 句
  • 虚函数:某基类中声明为 virtual 并一个或多个派生类中被重新定义的成员函数。...虚析构函数:释放派生类的对象。 C++规定,当一个成员函数被声明为虚函数之后,其派生类中的同名函数都自动成为虚函数。记住 ...
  • 创建类类型的新的对象的时候,都要执行类中的构造函数。而当构造函数中分配了资源之后,需要一个相应...另一方面,有基类和派生类存在创建派生类类型,会先构造基类,再构造派生类,析构顺序反之。 下面
  • 原因:多态情况,存在一种情况就是使用基类指针指向派生类对象,这样就可以实现多态使用。基类指针调用派生类函数。然而结束需要删除对象,这个时候如果直接使用基类指针删除对象,那么由于对象的指针作用...
  • (2)该对象的存在父类,当父类被释放时,其派生类也会被释放。 如,一个界面类A中,初始化另一个界面类B,要么就将这个界面类A作为界面B父类,然后delete界面类A。要么手动delete界面类B。 2、事件过滤器中...
  • Qt对象

    2021-03-14 15:47:08
    当创建的对象在堆区,如果指定的父亲是QObject派生下来的或者是QObject子类派生下来的,可以不用管理释放的操作,对象会被放入到对象树中。 一定程度上简化了内存回收机制 从QObject继承下来的控件,初始...
  • title date tags categories C++抽象类子类实例化的析构 2020-03-06 04:03:16 -0800 抽象类 ...C++使用抽象类会面临一个问题,根据其派生类实例出来的对象,如何释放内存,...
  • 就会调用该指针指向的派生类析构函数,而派生类的析构函数又自动调用基类的析构函数,这样整个派生类的对象完全被释放。如果析构函数不被声明成虚函数,则编译器实施静态绑定,删除基类指针,只会调用基类的析构...
  •  当我们希望使用容器来保存继承体系中的对象时,容器用于继承体系中的类型会有影响:派生类对象复制到基类对象时,派生类对象将被切掉。那么解决这一问题的方法通常是使用容器保存基类对象的指针,这些指针实际...
  • c++

    2013-03-16 20:05:18
    1.基类希望派生类重定义某个函数,则基类把该函数定义为virtual函数 ...4.当通过基类的引用或指针释放派生类的对象时,派生类的对象不能被释放 5.删除派生类对象时,基类对象被自动删除。
  • 1.1 当创建的对象在堆区,如果指定的父亲是QObject派生下来的或者Oobject子类派生下来的,可以不用管理释放的操作,对象会被放入对象树中,只要父类析构,子类亦会析构。一定程度上简化了内存回收机制 ...
  • 当创建的对象在堆区时候如果指定的父类是QObject派生下来的或者QObject子类派生下来的,可以不用管理释放的操作,将对象放入到对象树中。一定程度上简化了内存回收机制 当创建一个QObject对象时,会看到...
  • 首先,这里提到的继承都是公用继承。 派生类 1、派生类需要添加自己...4、释放对象时与创建相反,先调用派生类的析构函数再调用基类的析构函数。 关于派生类的使用: 1、派生类可以使用基类的非私有方法。 2、...
  • QT 对象数,窗口坐标系

    2019-12-17 21:39:45
    1、当创建的对象在堆区时候,如果指定的父亲QObject派生下来的或者QObject子类派生下来的,可以不用管理释放操作,将对象放入到对象树中。 2、一定程度上简化了内存回收机制 3、析构的顺序和创建顺序相反的...
  • Qt中QObject *parent内存释放注意事项

    千次阅读 2018-06-21 13:54:23
    QObject及其派生类的对象,如果其parent非0,那么其parent析构会析构该对象。 Qt中引入对象树 当一个 QObject 对象堆上创建的时候,Qt 会同时为其创建一个对象树。不过,对象树中对象的顺序是没有定义的。这...
  • 对象是由“底层向上”开始构造的,当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数,依次类推,直至到达派生类次数最多的派生次数最多的类的构造函数为止。因为,构造函数一开始构造时,...

空空如也

空空如也

1 2 3 4 5 ... 13
收藏数 249
精华内容 99
关键字:

在释放派生类的对象时