十七 物件的構造

2022-08-11 14:00:12 字數 4107 閱讀 8046

1、成員變數的初始值

#include class test

int getj()

};test gt; // 全域性物件 全域性區,統一初始值為0

int main()

2、物件的初始化

從程式設計的角度,物件只是變數,因此:

靜態儲存區包括了全域性變數和static修飾的區域性變數

需要解決的問題:使類的成員變數不管在哪個儲存區進行定義,它的初始值都是固定的。

物件的初始化:

#include class test

int getj()

void initialize()

};test gt;

int main()

這種方式存在的問題:

這個初始化函式在物件建立之手就必須馬上呼叫,新建物件之手,需要人工手動新增initialize()函式,如果可以有乙個函式在建立物件後自動呼叫,初始化成員變數就是極好的。

於是c++出現了建構函式來解決這個問題

3、建構函式

c++中可以定義與類名相同的特殊成員函式:建構函式

#include class test 

int getj()

void initialize()

// 建構函式

// 沒有返回值,名字和類名一樣

test()

};test gt;

int main()

4、帶引數的建構函式

建構函式和普通函式的差別:建構函式沒有返回值,名字和型別一樣

此時就只剩下引數可以討論:建構函式也可以帶引數

帶有引數的建構函式:

class test

};

注意:

物件定義和物件宣告不同:

test t;	// 定義物件並呼叫建構函式

int main()

建構函式的自動呼叫

class test 

test(int v)

test(const int& cv){} // 拷貝建構函式

}; test t; // 呼叫建構函式test()

test t1(1); // 定義了乙個物件t1,並呼叫帶有引數的建構函式,傳入引數為1,根據過載規則,建構函式為test(int v)

test t2 = 1; // 用 1 來初始化物件t2,初始化需要借助建構函式,根據過載規則,選擇test(int v)

/*這裡的過程其實是:

首先呼叫建構函式test(int v)建立乙個臨時物件,引數為1;

然後就變成了用乙個物件初始化另乙個物件,此時應該是要呼叫拷貝建構函式進行成員變數值的複製,將這個臨時物件作為引數用來構造物件t2。

但是編譯器發現,可以通過過載的建構函式test(int v)來直接初始化物件,而達到相同效果,所以將這條語句優化為test t1(1)

*/

初始化和賦值:

#include class test

test(int v)

};int main()

初始化和賦值是不一樣的,c語言中差別不大,c++中差別很大,因為物件的初始化要呼叫建構函式

建構函式的呼叫:

5、建立乙個陣列

#include class test

test(int v)

void getvalue()

};int main()

; // 手工呼叫建構函式,3個陣列元素呼叫不同的建構函式

for (int i = 0; i < 3; i++)

test t = test(100); // 建立物件之後,呼叫建構函式來初始化物件

return 0;

}

需求:開發乙個陣列類解決原生陣列的安全性問題

// intarray.h

#ifndef _intarray_h_

#define _intarray_h_

class intarray

;#endif

// intarray.c

#include "intarray.h"

// 建構函式

intarray::intarray(int len)

m_length = len;

}int intarray::length()

bool intarray::get(int index, int& value)

return ret;

}bool intarray::set(int index, int value)

return ret;

}// 用來釋放對空間

void intarray::free()

// main.c

#include #include "intarray.h"

int main()

for (int i = 0; i < a.length(); i++) }

a.free();

return 0;

}

6、特殊的建構函式

兩個特殊的建構函式

如果類中已經有建構函式,編譯器就不會提供預設的建構函式

#include class test

int getj()

/*test(){}; // 編譯器會提供乙個預設的無參建構函式

*/// 拷貝建構函式,這也是乙個建構函式,寫了這個之後,編譯器就不會提供預設的無參建構函式,建立物件就會失敗,需要手工再建立乙個無參建構函式

test(const test& t)

test(){};

};class t

int main()

拷貝建構函式的意義:

初始化和賦值不一樣的地方在於,初始化涉及到拷貝建構函式的呼叫,通過拷貝建構函式可以利用乙個已知的物件去建立初始化乙個新的物件

拷貝建構函式分為:

編譯器提供的拷貝建構函式只進行淺拷貝

#include class test

int getj()

int* getp()

// 手工構造乙個拷貝建構函式

/* 深拷貝:深入到了對應的堆空間記憶體中的值

*/test(const test& t)

// 定義乙個帶引數的建構函式

test(int v)

void free()

};int main()

/* t1.i = 1, t1.j = 2, t1.p = 0x8528008

t2.i = 1, t2.j = 2, t2.p = 0x8528018

這就是物理狀態,就是物件佔據的記憶體中,他們的每個位元組是否相等

t1和t2這兩個物件在記憶體中佔據的空間中的值是不一樣的

從另乙個角度看

t1.i = 1, t1.j = 2, *t1.p = 3

t2.i = 1, t2.j = 2, *t2.p = 3

這就是邏輯狀態,t1和t2是一樣的,我們需要的僅僅是t1和t2的p指標,所指向的空間中的值是一樣的

*/

什麼時候使用深拷貝:物件中有成員指向了系統資源

一般性原則:自定義拷貝建構函式,必然需要實現深拷貝!!!

7、陣列類的改進
// intarray.c

// 建構函式

intarray::intarray(int len)

m_length = len;

}// 新增拷貝建構函式,深拷貝

intarray::intarray(const intarray& obj)

}

8、小結

十七 物件的構造

1 成員變數的初始值 include class test int getj test gt 全域性物件 全域性區,統一初始值為0 int main 2 物件的初始化 從程式設計的角度,物件只是變數,因此 靜態儲存區包括了全域性變數和static修飾的區域性變數需要解決的問題 使類的成員變數不管在哪...

練習三十七 對獲取資料進行排序

1 n 10 2 print 輸入10個要進行判斷的數字 3 l 4 for i in range n 6 print l 7 for i in range n 1 8 min i 9 for j in range i,n 10 if l min l j 11 min j 12 l i l min ...

物件的構造

構造物件時對物件的初始化,構造物件時被jvm自動呼叫 1.方法名與類名相同 2.沒有返回值 3.定義乙個類時,系統會預設提供乙個無參的建構函式,當使用者自定義了有參的建構函式時,無參的建構函式會被覆蓋 例如 public myclass 形參 new 建構函式時 1.根據建構函式找到建構函式所屬的類...