[TOC] 1. 析構函數 C++的類中可以定義一個特殊的清理函數,叫做析構函數,語法規則為 析構函數沒有參數,也沒有返回值類型聲明 析構函數在對象銷毀時自動被調用 當類中自定義了構造函數,並且構造函數中使用了系統資源(如:堆空間、文件打開,等),則需要自定義析構函數 2. 對象的構造與析構順序 多 ...
目錄
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 = %d\n", 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 = %p\n", this); //每個成員函數中隱藏了一個this指針,用於指向當前對象
}
int main()
{
Test t1(1);
Test t2(2);
Test t3(3);
printf("t1.getMi() = %d\n", t1.getMi());
printf("&t1 = %p\n", &t1);
t1.print();
printf("t2.getMi() = %d\n", t2.getMi());
printf("&t2 = %p\n", &t2);
t2.print();
printf("t3.getMi() = %d\n", t3.getMi());
printf("&t3 = %p\n", &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] = %d\n", i, value);
}
}
IntArray b = a;
for(int i = 0; i < b.length(); i++)
{
int value = 0;
if( b.get(i, value) )
{
printf("b[%d] = %d\n", i, value);
}
}
return 0;
}