­

对象的构造与析构(二)

  • 2019 年 10 月 3 日
  • 筆記

1. 析构函数

  • C++的类中可以定义一个特殊的清理函数,叫做析构函数,语法规则为~ClassName()
  • 析构函数没有参数,也没有返回值类型声明
  • 析构函数在对象销毁时自动被调用
  • 当类中自定义了构造函数,并且构造函数中使用了系统资源(如:堆空间、文件打开,等),则需要自定义析构函数

2. 对象的构造与析构顺序

多个对象之间

多个对象构造时:

  • 栈对象的构造顺序依赖于程序的执行流
  • 堆对象的构造顺序依赖于new的使用顺序
  • 全局对象的构造顺序是不确定的,不同的编译器可能使用不同的规则

多个对象析构时:

  • 栈对象和全局对象的析构顺序与构造顺序相反
  • 堆对象的析构发生取决于delete的使用顺序

单个对象内部

单个对象创建时,对象内部构造函数的调用顺序为:

  • 先调用父类的构造函数
  • 再调用成员变量的构造函数,调用顺序与声明顺序相同
  • 最后调用类自身的构造函数

单个对象内部的析构顺序与构造顺序相反。

3. const对象与const成员函数

const对象

  • 由const关键字修饰的对象为只读对象
  • 只读对象的成员变量不允许被改变
  • 只读属性只在编译阶段有效,运行时无效

const成员函数

const成员函数的定义如下所示,需要注意的是,函数声明和函数定义都必须带const关键字。

Type ClassName :: func(Type para) const

关于const成员函数的使用,有下面几条规则:

  • const对象只能调用const成员函数
  • const成员函数只能调用const成员函数
  • const成员函数不能直接修改成员变量的值
#include <stdio.h>    class Test  {      int mi;  public:      Test(int i);      void setMi(int i) const;      int getMi() const;      void printMi();  };    Test::Test(int i)  {      mi = i;  }    void Test::setMi(int i) const  {      mi = i;  //Error,const成员函数中不能直接修改成员变量的值  }    int Test::getMi() const  {      return mi;  }    void Test::printMi()  {      printf("printMi(): mi = %dn", mi);  }    int main()  {      const Test t1(1);        t1.getMi();    //OK,const对象调用const成员函数      t1.printMi();  //Error,const对象调用普通成员函数        return 0;  }

4. 成员函数、成员变量与对象的关系

面向对象的角度,对象由属性(成员变量)方法(成员函数)构成;
程序运行的角度,对象由数据函数构成,数据位于栈、堆或全局数据区,函数位于代码段。

  • 每一个对象都拥有自己独立的属性(成员变量)
  • 所有的对象共享类的方法(成员函数)
  • 方法能够直接访问对象的属性
  • 方法中的隐藏参数this指针用于值代当前对象
#include <stdio.h>    class Test  {      int mi;  public:      int mj;      Test(int i);      Test(const Test &t);      int getMi();      void print();  };    Test::Test(int i)  {      mi = i;  }    Test::Test(const Test &t)  {      mi = t.mi;  //成员函数可以直接访问对应类对象的成员变量  }    int Test::getMi()  {      return mi;  }    void Test::print()  {      printf("this = %pn", this);  //每个成员函数中隐藏了一个this指针,用于指向当前对象  }    int main()  {      Test t1(1);      Test t2(2);      Test t3(3);        printf("t1.getMi() = %dn", t1.getMi());      printf("&t1 = %pn", &t1);      t1.print();        printf("t2.getMi() = %dn", t2.getMi());      printf("&t2 = %pn", &t2);      t2.print();        printf("t3.getMi() = %dn", t3.getMi());      printf("&t3 = %pn", &t3);      t3.print();        return 0;  }

5. 代码实战——数组类IntArray

IntArray.h

#ifndef _INTARRAY_H_  #define _INTARRAY_H_    class IntArray  {  private:      int m_length;      int *m_pointer;  public:      IntArray(int len);      IntArray(const IntArray &obj);      int length();      bool get(int index, int &value);      bool set(int index ,int value);      ~IntArray();  };    #endif

IntArray.cpp

#include "IntArray.h"    IntArray::IntArray(int len)  {      m_pointer = new int[len];        for(int i=0; i<len; i++)      {          m_pointer[i] = 0;      }        m_length = len;  }    IntArray::IntArray(const IntArray &obj)  {      m_length = obj.m_length;        m_pointer = new int[obj.m_length];        for(int i = 0; i < obj.m_length; i++)      {          m_pointer[i] = obj.m_pointer[i];      }  }    int IntArray::length()  {      return m_length;  }    bool IntArray::get(int index, int &value)  {      bool ret = (0 <= index) && (index < length());        if( ret )      {          value = m_pointer[index];      }        return ret;  }    bool IntArray::set(int index, int value)  {      bool ret = (0 <= index) && (index < length());        if( ret )      {          m_pointer[index] = value;      }        return ret;  }    IntArray::~IntArray()  {      delete[] m_pointer;  }

IntArray测试

#include "IntArray.h"  #include <stdio.h>    int main()  {      IntArray a(5);        for(int i = 0; i < a.length(); i++)      {          a.set(i, i + 1);      }        for(int i = 0; i < a.length(); i++)      {          int value = 0;            if( a.get(i, value) )          {              printf("a[%d] = %dn", i, value);          }      }        IntArray b = a;        for(int i = 0; i < b.length(); i++)      {          int value = 0;            if( b.get(i, value) )          {              printf("b[%d] = %dn", i, value);          }      }        return 0;  }