1. 程式人生 > >C++基礎第三章(使用類和物件)上篇

C++基礎第三章(使用類和物件)上篇

利用建構函式對類物件初始化

在類內如果資料成員是公有的則可以在類內直接進行初始化

#include<iostream>
using namespace std;
class Time 
{
	public :
		int hour = 1;
		int minute = 0;
		int sec = 0;	
};

int main()
{
	Time t1;
	cout << t1.hour << endl;
	return 0;
}

或者這樣

#include<iostream>
using namespace std;
class Time 
{
	public :
		int hour;
		int minute;
		int sec;	
};

int main()
{
	Time t1 = {1, 1, 1};
	cout << t1.hour << endl;
	return 0;
}

上述初始化是從上到下,從左到右對應的,有順序。

但是如果資料成員是 private 或者是 protected;就不能再這樣初始化

#include<iostream>
using namespace std;

class Time 
{
	private:
	int hour = 0;	//錯誤,私有資料成員 
};

int main()
{
	Time t1 = {1};	//或者這樣都是錯誤的 
	return 0;
}

一.1 , 建構函式實現資料成員的初始化

建構函式是一種特殊的成員函式,與其他成員函式不同,不需要使用者來呼叫,而是在建立物件時自動執行

建構函式的名字必須與類名相同。

#include<iostream>
using namespace std;

class Time 
{
	public:
		Time()
		{
			hour = 0;
			sec = 1;
			minute = 0;
		}
		void set_time();
		void show_time();
	private:
		int hour;
		int minute;
		int sec;
};

void Time::set_time()
{
	cin >> hour >> minute >> sec;
}
void Time::show_time()
{
	cout << hour << " : " << minute << " : " << sec << endl; 
}

int main()
{
	Time t1, t2;
	t1.set_time();
	t1.show_time();
	t2.show_time();
	return 0;
}

類外定義類內宣告 Time();

Time::Time()
{
	hour = 0;
	sec = 1;
	minute = 0;
}

建構函式不能被呼叫,可以使用一個類的物件初始化另一個物件

Time t1;
t1.Time();        //不能呼叫建構函式
	
Time t2 = t1;    //一個類物件可以初始化另一個類物件

一.2 , 帶引數的建構函式

Time(int, int, int);        //類內宣告

Time::Time(int h, int m, int s)    //類外定義
{
	hour = h;
	minute = m;
	sec = s;
}

Time t1(5, 5, 5);        //傳參
Time(int h, int m, int s)    //類內定義
{
	hour = h;
	minute = m;
	sec = s;
}

一.3,用引數初始化表對資料成員初始化

引數初始化表

Box::Box(int h, int w, int len):heigh(h), width(w), length(len){}

帶有引數初始化表的建構函式的一般形式如下:

類名::建構函式名( [ 引數表 ] )[ :成員函式初始化表 ]

{

[ 建構函式體]

}

如果資料成員是陣列,則應當在建構函式的函式體中用語句對其賦值,而不能在引數初始化表中對其初始化

#include<iostream>
#include<stdio.h>
#include<string.h>

using namespace std;
class Student
{
	public:
		Student(int n, char s,char nam[]):num(n), sex(s)
		{
			strcpy(name,nam);
		}
		void show()
		{
			cout << name << endl;
		}
	private:
		int num;
		char sex;
		char name[20];
};

int main()
{
	Student stud1(1111, 'm', "WangLin");
	stud1.show();
	return 0;
}

一.4,建構函式的過載

class Box
{
	public:
		Box();
		Box(int h, int w, int len):height(h), width(w), length(len){}
	private:	
		int height;
		int width;
		int length;
};

Box::Box()
{
	height = 10;
	width = 11;
	length = 5;	
} 
Box(int);            //有一個引數的建構函式   
Box(int, int);       //有兩個引數的建構函式

在建立物件時不必給出實參的建構函式,成為預設建構函式(default constructor),顯然無參建構函式是預設建構函式,一個類只能有一個預設建構函式。如果使用者沒有定義,系統會自動定義,但是它的函式體是空的,不起初始化的作用。如果你想要有初值,就需要自己初始化。

一.5,使用預設引數的建構函式

class Box
{
	public:
		Box(int h = 10, int w = 10, int len = 10);
	private:	
		int height;
		int width;
		int length;
};

Box::Box(int h, int w, int len):height(h), width(w), length(len){}

int main ()
{
	Box box1;		//不傳遞引數 
	Box box2(10);		//只傳遞一個引數 
	Box box3(10, 15);	//傳遞2個引數 
	Box box4(10, 15, 30);	//傳遞3個引數 
}

在宣告建構函式時,形參名字可以省略

Box(int = 10, int = 5, int = 6) 

下面給出不能進行過載的例子

Box()
Box(int = 10, int = 5, int = 6) 

原因:預設構造引數只能有一個,上面是錯誤的

Box()
Box(int = 10, int = 5, int = 6) 
Box(int ,int)

Box box1;        //是呼叫1還是2?
Box box2(10, 5); //是呼叫2還是3?

原因:在一個類中定義了一個全部是預設構造後,不能在定義過載建構函式

Box()
Box(int , int = 5, int = 6) 
Box(int ,int)

Box box1(10, 5);    //錯誤,出現歧義性

一.6,利用解構函式進行清理工作

解構函式的作用: 並不是刪除物件而是在撤銷物件佔用物件的記憶體之前完成一些清理工作,使這部分記憶體可以被程式分配給新的物件使用。程式設計者要事先設計好解構函式,已完成所需功能,只要物件生命期結束,程式就會自動執行函式完成這些工作

當物件的生命期結束,會自動執行解構函式、

(1) 如果在一個函式中定義了一個物件(假設是自動區域性物件),當這個函式被呼叫結束時,物件應該被釋放,在物件釋放前自動執行解構函式。

(2)靜態(static)區域性物件在函式呼叫結束時物件並不釋放,因此也不調解構函式,只在main函式結束或呼叫exit函式結束程式時,才呼叫static區域性對物件的解構函式。

(3)如果定義一個全域性物件,則在程式的流程離開其作用域時(如main函式結束或呼叫exit函式)時,呼叫該全域性物件的解構函式。

(4)如果用new運算子動態地建立了一個物件,當用delete運算子釋放該物件時,先呼叫該物件的解構函式

解構函式不返回任何值,沒有函式型別,也沒有函式引數,不能被過載,一個函式可以有多個建構函式,但是解構函式只能有一個。

並且解構函式的用不值是釋放資源,還可以用來執行“使用者希望在最後一次使用物件之後所執行的任何操作”。你也可以在解構函式內寫函式 呼叫資料。

如果使用者沒有定義解構函式c++ 編譯系統會自動生成但是它只是徒有其名,什麼操作都不進行,想讓解構函式完成任何工作都必須在定義的解構函式內指定。

#include<iostream>
#include<string>
using namespace std;
class Student
{
	public:
		Student(int , string , string);
		~Student();                //解構函式
		void display();
	private:
		int num;
		string name;
		string sex;
};
Student::Student(int n, string nam, string s)
{
	num = n;
	name = nam;
	sex = s;
	cout << "Constructor called." << endl;
}
Student::~Student()
{
	cout << "Destructor called." << num << endl;
}
void Student::display()
{
	cout << "number = " << num << endl;
	cout << "name = " << name << endl;
	cout << "sex = " << sex << endl;	
}
int main(){
	Student stud1(1001,"小明","man");
	stud1.display();
	Student stud2(1002,"小芳","woman");
	stud2.display();
} 

發現解構函式執行的順序了麼?

呼叫建構函式和解構函式的順序

先構造的後析構,後構造的先析構

(1)如果在全域性範圍中定義物件(就是函式外),他的建構函式在本檔案中所有函式執行前呼叫,但是一個程式若包含很多個檔案,而不同的檔案中有定義了全域性物件,則他們執行建構函式的順序不確定。他們都是在main執行完畢或呼叫exit函式時呼叫解構函式。

(2)如果定義的是區域性自動物件(在函式內定義),則在建立物件時呼叫其建構函式。如果物件所在函式被多次呼叫,則每次建立物件時都要呼叫建構函式,在函式呼叫結束時,物件釋放時呼叫解構函式。

(3)如果定義靜態(static)區域性物件,則只在程式第一次呼叫此函式定義物件時呼叫建構函式一次即可,在函式呼叫結束時物件並不釋放,因此也不呼叫解構函式,只在main函式呼叫結束或exit函式結束時呼叫。

例子

void funtion()
{
	Student stud1;
	static Student stud2;
	
}

當呼叫到funtion函式時,先建立物件stud1,然後執行stud1的建構函式,然後建立物件stud2,然後執行stud2的建構函式。當funtion函式執行完後,呼叫stud1的解構函式,而stud2是靜態區域性物件在funtion結束後並不釋放物件.直到整個程式結束時stud2才釋放,執行解構函式。