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才釋放,執行解構函式。