精华内容
下载资源
问答
  • 什么时候要虚析构函数?

    千次阅读 2017-05-27 13:20:13
    一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而千万内存泄漏。 原因: 在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要...
     什么时候要用虚析构函数?
    通过基类的指针来删除派生类的对象时,基类的析构函数应该是虚的。否则其删除效果将无法实现。
    一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而千万内存泄漏。
    原因:
    在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要用基类对非继承成员进行操作,则要把基类的这个操作(函数)定义为虚函数。
    那么,析构函数自然也应该如此:如果它想析构子类中的重新定义或新的成员及对象,当然也应该声明为虚的。
    注意:
    如果不需要基类对派生类及对象进行操作,则不能定义虚函数(包括虚析构函数),因为这样会增加内存开销。
    语法如下:
    class Base
    ...{ public:
           Base( ) ...{   };
       virtual     ~Base( ) ...{   };   //注意:基类的析构函数被定义为虚的
    };
    class Derived
    ...{
       public:
           Derived( ) ...{   };
         ~Derived( ) ...{   };
    };
    void main( )
    ...{
       Base *p;
       p = new Derived;
       delete p;
    }
    注:似乎这样的使用经常在new和delete行为时。
    =================================================
    我们知道,用C++开发的时候,用来做基类的类的析构函数一般都是虚函数。可是,为什么要这样做呢?下面用一个小例子来说明:    
         有下面的两个类:
    class ClxBase
    {
    public:
         ClxBase() {};
         virtual ~ClxBase() {};
         virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
    };
    class ClxDerived : public ClxBase
    {
    public:
         ClxDerived() {};
         ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };
         void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };
    };
         代码
    ClxBase *pTest = new ClxDerived;
    pTest->DoSomething();
    delete pTest;
         的输出结果是:
    Do something in class ClxDerived!
    Output from the destructor of class ClxDerived!
         这个很简单,非常好理解。
         但是,如果把类ClxBase析构函数前的virtual去掉,那输出结果就是下面的样子了:
    Do something in class ClxDerived!
    也就是说,类ClxDerived的析构函数根本没有被调用!一般情况下类的析构函数里面都是释放内存资源,而析构函数不被调用的话就会造成内存泄漏。我想所有的C++程序员都知道这样的危险性。当然,如果在析构函数中做了其他工作的话,那你的所有努力也都是白费力气。
         所以,文章开头的那个问题的答案就是--这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。
         当然,并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。
    写成虚的是为了在实现多态的时候不造成内存泄露, 比如:
    class a
    {
    int aa;
    public:
    virtual ~a(){};
    };
    class b : public a
    {
    int bb;
    };
    如果你这样:
    a *pa = new b; // upcast
    然后这样:
    delete pa;
    这句delete, 如果你基类的析构函数不是虚的的话, 就会造成内存泄露, 具体表现为派生类的内存被释放了而基类没有.(疑问:似乎应该是基类内存释放而派生类内存没有释放)
    //参考资料的地方, Efftive C++
    在继承中使用多态来创建动态对象时, 比如上面的:a *pa = new b;
    由于pa是个基类的指针, 只能识别属于基类的部分, 所以如果没有虚析构函数的话, 那么子类中特有的部分就不会被释放, 造成"经典"的释放一半, 泄露一半的内存泄露.
    这和object slicing的原理是一样的, 至于object slicing:
    为什么继承一个没有虚析构函数的类是危险的?
      一个没有虚析构函数的类意味着不能做为一个基类。如std::string,  
    std::complex, 和 std::vector 都是这样的。为什么继承一个没有虚析构函数的
    类是危险的?当你公有继承创建一个从基类继承的相关类时,指向新类对象中的指
    针和引用实际上都指向了起源的对象。因为析构函数不是虚函数,所以当你delete
    一个这样的类时,C++就不会调用析构函数链。
    class A
    {
     public:
     ~A() // 不是虚函数
     {
     // ...
     }
    };  
    class B: public A //错; A没有虚析构函数
    {
     public:
     ~B()
     {
     // ...
     }
    };
    int main()
    {
     A * p = new B; //看上去是对的
     delete p; //错,B的析构函没有被调用
    }
    展开全文
  • 一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而千万内存泄漏。 原因: 在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。...

    什么时候要用虚析构函数?
    通过基类的指针来删除派生类的对象时,基类的析构函数应该是虚的。否则其删除效果将无法实现。
    一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而千万内存泄漏。
    原因:
    在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要用基类对非继承成员进行操作,则要把基类的这个操作(函数)定义为虚函数。
    那么,析构函数自然也应该如此:如果它想析构子类中的重新定义或新的成员及对象,当然也应该声明为虚的。
    注意:
    如果不需要基类对派生类及对象进行操作,则不能定义虚函数(包括虚析构函数),因为这样会增加内存开销。
    语法如下:
    class Base
    ...{ public:
           Base( ) ...{   };
       virtual     ~Base( ) ...{   };   //注意:基类的析构函数被定义为虚的
    };
    class Derived
    ...{
       public:
           Derived( ) ...{   };
         ~Derived( ) ...{   };
    };
    void main( )
    ...{
       Base *p;
       p = new Derived;
       delete p;
    }
    注:似乎这样的使用经常在new和delete行为时。
    =================================================
    我们知道,用C++开发的时候,用来做基类的类的析构函数一般都是虚函数。可是,为什么要这样做呢?下面用一个小例子来说明:    
         有下面的两个类:
    class ClxBase
    {
    public:
         ClxBase() {};
         virtual ~ClxBase() {};
         virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
    };
    class ClxDerived : public ClxBase
    {
    public:
         ClxDerived() {};
         ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; };
         void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };
    };
         代码
    ClxBase *pTest = new ClxDerived;
    pTest->DoSomething();
    delete pTest;
         的输出结果是:
    Do something in class ClxDerived!
    Output from the destructor of class ClxDerived!
         这个很简单,非常好理解。
         但是,如果把类ClxBase析构函数前的virtual去掉,那输出结果就是下面的样子了:
    Do something in class ClxDerived!
    也就是说,类ClxDerived的析构函数根本没有被调用!一般情况下类的析构函数里面都是释放内存资源,而析构函数不被调用的话就会造成内存泄漏。我想所有的C++程序员都知道这样的危险性。当然,如果在析构函数中做了其他工作的话,那你的所有努力也都是白费力气。
         所以,文章开头的那个问题的答案就是--这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。
         当然,并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。
    写成虚的是为了在实现多态的时候不造成内存泄露, 比如:
    class a
    {
    int aa;
    public:
    virtual ~a(){};
    };
    class b : public a
    {
    int bb;
    };
    如果你这样:
    a *pa = new b; // upcast
    然后这样:
    delete pa;
    这句delete, 如果你基类的析构函数不是虚的的话, 就会造成内存泄露, 具体表现为派生类的内存被释放了而基类没有.(疑问:似乎应该是基类内存释放而派生类内存没有释放)
    //参考资料的地方, Efftive C++
    在继承中使用多态来创建动态对象时, 比如上面的:a *pa = new b;
    由于pa是个基类的指针, 只能识别属于基类的部分, 所以如果没有虚析构函数的话, 那么子类中特有的部分就不会被释放, 造成"经典"的释放一半, 泄露一半的内存泄露.
    这和object slicing的原理是一样的, 至于object slicing:
    为什么继承一个没有虚析构函数的类是危险的?
      一个没有虚析构函数的类意味着不能做为一个基类。如std::string,  
    std::complex, 和 std::vector 都是这样的。为什么继承一个没有虚析构函数的
    类是危险的?当你公有继承创建一个从基类继承的相关类时,指向新类对象中的指
    针和引用实际上都指向了起源的对象。因为析构函数不是虚函数,所以当你delete
    一个这样的类时,C++就不会调用析构函数链。
    class A
    {
     public:
     ~A() // 不是虚函数
     {
     // ...
     }
    };  
    class B: public A //错; A没有虚析构函数
    {
     public:
     ~B()
     {
     // ...
     }
    };
    int main()
    {
     A * p = new B; //看上去是对的
     delete p; //错,B的析构函没有被调用
    }

    展开全文
  • 为何要析构函数

    2017-02-03 11:08:08
    一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而千万内存泄漏。 原因: 在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要...
    <新学到浅拷贝和深拷贝>


    一.什么时候要用虚析构函数?

    通过基类的指针来删除派生类的对象时,基类的析构函数应该是虚的。否则其删除效果将无法实现。

    一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而千万内存泄漏。

    原因:

    在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要用基类对非继承成员进行操作,则要把基类的这个操作(函数)定义为虚函数。

    那么,析构函数自然也应该如此:如果它想析构子类中的重新定义或新的成员及对象,当然也应该声明为虚的。

    注意:

    如果不需要基类对派生类及对象进行操作,则不能定义虚函数(包括虚析构函数),因为这样会增加内存开销。

    语法如下:

    class Base

    ...{ public:

    Base( ) ...{ };

    virtual ~Base( ) ...{ }; //注意:基类的析构函数被定义为虚的

    };

    class Derived

    ...{

    public:

    Derived( ) ...{ };

    ~Derived( ) ...{ };

    };

    void main( )

    ...{

    Base *p;

    p = new Derived;

    delete p;

    }

    注:似乎这样的使用经常在new和delete行为时。

    2.另解

    我们知道,用C 开发的时候,用来做基类的类的析构函数一般都是虚函数。可是,为什么要这样做呢?下面用一个小例子来说明:

    有下面的两个类:

    class ClxBase

    {

    public:

    ClxBase() {};

    virtual ~ClxBase() {};

    virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl;

    };



    class ClxDerived : public ClxBase

    {

    public:

    ClxDerived() {};

    ~ClxDerived() {

    cout << "Output from the destructor of class ClxDerived!" << endl;

    };

    void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };

    };

    代码

    ClxBase *pTest = new ClxDerived;

    pTest->DoSomething();

    delete pTest;

    的输出结果是:

    Do something in class ClxDerived!

    Output from the destructor of class ClxDerived!

    这个很简单,非常好理解。

    但是,如果把类ClxBase析构函数前的virtual去掉,那输出结果就是下面的样子了:

    Do something in class ClxDerived!

    也就是说,类ClxDerived的析构函数根本没有被调用!一般情况下类的析构函数里面都是释放内存资源,而析构函数不被调用的话就会造成内存泄漏。我想所有的C 程序员都知道这样的危险性。当然,如果在析构函数中做了其他工作的话,那你的所有努力也都是白费力气。

    所以,文章开头的那个问题的答案就是--这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。

    当然,并不是要把所有类的析构函数都写成虚函数。

    因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。

    写成虚的是为了在实现多态的时候不造成内存泄露, 比如:

    class a

    {

    int aa;

    public:

    virtual ~a(){};

    };

    class b : public a

    {

    int bb;

    };

    如果你这样:

    a *pa = new b; // upcast

    然后这样:

    delete pa;

    这句delete, 如果你基类的析构函数不是虚的的话, 就会造成内存泄露, 具体表现为派生类的内存被释放了而基类没有.(疑问:似乎应该是基类内存释放而派生类内存没有释放)
    展开全文
  • 一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而造成内存泄漏。 原因: 在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要...

    通过基类的指针来删除派生类的对象时,基类的析构函数应该是虚的。否则其删除效果将无法实现

     就像下面的的例子A *p = new B; delete p; ,基类A的构造函数和析构调用啦,但是派生类B只能调用构造函数却不能调用析构函数(析构函数就是用啦删除对象的)

    一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而造成内存泄漏。

    原因:
    在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要用基类对非继承成员进行操作,则要把基类的这个操作(函数)定义为虚函数。那么,析构函数自然也应该如此:如果它想析构子类中的重新定义或新的成员及对象,当然也应该声明为虚的。

    注意:
    如果不需要基类对派生类及对象进行操作,则不能定义虚函数(包括虚析构函数),因为这样会增加内存开销。

    语法如下: 

    {
      public:
       A(){cout << "In A constructor" << endl;}
       ~A(){cout << "In A destructor" << endl;}
      };
      
      class B : public A
      {
      public:
       B()
       {
       cout << "In B constructor" << endl;
       m_p = new char[10];
       }
       ~B()
       {
       cout << "In B destructor" << endl;
       if (m_p) delete [] m_p;
       }
      private:
       char *m_p;
      };
      
      int main(int argc, char* argv[])
      {
       //printf("Hello World!\n");
       A *p = new B;
       delete p;
      
       return 0;
      }
      输出结果:
      In A constructor
      In B constructor
      In A destructor
    
    并没有调用B的析构函数,new出来的内存没有及时回收造成内存泄漏。


    C++中虚析构函数的作用

    所以,文章开头的那个问题的答案就是--这样做是为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。
    当然,并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。

    写成虚的是为了在实现多态的时候不造成内存泄露, 比如: 

    class a 
    { 
    int aa; 
    public: 
    virtual ~a(){}; 
    }; 
    
    class b : public a 
    { 
    int bb; 
    }; 
    
    如果你这样: 
    
    a *pa = new b; // upcast 
    
    然后这样: 
    
    delete pa; 
    

    这句delete, 如果你基类的析构函数不是虚的的话, 就会造成内存泄露, 具体表现为基类的内存被释放了而派生类没有

    在继承中使用多态来创建动态对象时, 比如上面的:a *pa = new b;
    由于pa是个基类的指针, 只能识别属于基类的部分, 所以如果没有虚析构函数的话, 那么子类中特有的部分就不会被释放, 造成"经典"的释放一半, 泄露一半的内存泄露.

    我的编译器警告级别被我调成最高, 有一次写类多态的时候它就警告我base类中没有虚的虚构函数, 我开始也不懂为什么, 但既然警告了就说明一定有问题, 后来查了资料就知道了, 自己也长了见识. 

     总之一句话:只要一个类要作为其他类的基类, 那么它就一定有虚函数, 只要一个类中有虚函数, 那么它的析构函数就一定也要是虚的, 否则就会造成我以上所说的问题, 


    展开全文
  • 电脑开机不能进入系统--死机

    万次阅读 2007-06-17 09:12:00
    我一查看,当电脑启动到一半时就死机,一动不动,系统WIN2000。我打开机箱,把内存条拔出,橡皮擦干净,又插回,重新启动,还是不行。试了其它的操作系统修复软件来修复,没用,于是进入安全模式,正常进入...
  • 一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而千万内存泄漏。 原因: 在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要...
  • C++中虚析构函数的作用(1)(转)

    千次阅读 2008-03-05 21:08:00
    一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半形象,从而千万内存泄漏。原因:在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要基类对...
  • 4.4.4 JVM内存为什么要分成新生代,老年代,持久代。新生代中为什么要分为Eden和Survivor。 4.4.5 JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代,说说你知道的几种主要的JVM参数。 4.4.6 你知道哪几种...
  • 至于为什么要把String类设计成不可变类,是它的用途决定的。其实不只String,很多Java标准类库中的类都是不可变的。在开发一个系统的时候,我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想的...
  •  至于为什么要把String类设计成不可变类,是它的用途决定的。其实不只String,很多Java标准类库中的类都是不可变的。在开发一个系统的时候,我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想...
  • 史上超高压缩软件2009

    2009-09-04 14:46:16
    -------------------------------------------------------------------------------------- 最新更新情况: 0.260 新内核的正式版,也是UDA的第三个正式版....2.问:UDA压缩或解压时为什么很慢? 答:UDA使用的压缩...
  • 当一个Windows函数返回一个错误代码时,它常常可以用来了解函数为什么会运行失败。Microsoft公司编译了一个所有可能的错误代码的列表,并且为每个错误代码分配了一个32位的号码。 从系统内部来讲,当一个Windows函数...
  • 为什么其它群的话单正常,唯独11群不正常呢?11群是四个群中最小的群,其中继计次表位于缓冲区的首位,打完电话后查询内存发现出中继群号在内存中是正确的,取完话单后再查就不正确了。 结 论: 话单池的一个备份...
  • wap网站和wap+2.0教程.

    2011-01-08 10:38:53
    在不久的将来,市场对WAP设备的要求会以浏览器的显示屏尺寸、输入装置及内存大小等不同根据,从而促使WAP设备在新技术及解决方案上得以发展进步。  通过使用移动电话连上互联网不久将成为一种标准,而WAP就是实现...
  • 相关知识你可以看看我的这两篇文章:【Android内存基础——内存抖动http://www.jianshu.com/p/69e6f894c698】【两张图告诉你,为什么你的App会卡顿?http://www.jianshu.com/p/df4d5ec779c8】响应触摸事件如果你...
  • 被攻击的主机资源被耗尽,主机也就没什么用处了。如果发送有足够数量的 S Y N报文,则某 些操作系统也会崩溃,并且需要重启系统。 这就是常见的D o S攻击,这种攻击本身破坏性极强,而且它有时也作为更复杂的攻击的...
  • 大话数据结构

    2018-12-14 16:02:18
    求100个人的高考成绩平均分与求全省所有考生的成绩平均分在占用时间和内存存储上有非常大的差异,我们自然追求高效率和低存储的算法来解决问题。 2.6.1正确性 22 2.6.2可读性 23 2.6.3健壮性 23 2.6.4时间效率高...

空空如也

空空如也

1 2
收藏数 24
精华内容 9
关键字:

为什么内存只能用一半