前言
? ? ? ?"打牢基礎,萬事不愁" .C++的基礎語法的學習
引入
? ? ? ? 類是實現面向對象思想的主要方法.前面提到:類是函數的變種,類可以通過調用靜態方法或者成員函數來實現邏輯.多數情況下使用成員函數.構造函數是生成類對象成員的必須條件,對此做一些構造函數的歸納
構造函數的目的
? ? ? ?接續:做每件事之前都想想目標是什么.學習也是一樣,想想設計者的思路是什么.?
? ? ? ? 通常情況下類有成員屬性和成員函數.構造函數的目的是為了初始化屬性(給屬性賦初值)
構造函數的形式
? ? ? ? 1>直接賦值:最直觀的形式,也是用得最多的一種,傳入的?形參等于屬性值????????
? ? ? ? 舉例:?
class PersonDirect {std::string name;int age;
public:PersonDirect(const std::string& str,int ag):name(str),age(ag){}
};
?????????調用構造函數生成對象,將名稱和年齡傳入????????
PersonDirect zs_d("張三",40); //創建一個對象,姓名"張三",年齡40
? ? ? ? 2>部分賦值,不給屬性賦初值也可以.
????????舉例:
class PersonDirectSome {string name;int age;
public:PersonDirectSome(const string& str) :name(str) {} //沒有給屬性age賦初值void setAge(int ag) { age = ag; } //設置屬性age的值int getAge() const { return age; } //讀取屬性age的值
};
? ? ? ? 調用構造函數時,傳入名稱
PersonDirectSome zs_ds("張三");zs_ds.setAge(45);cout << zs_ds.getAge() << endl;
?? ? ? ? 生成對象時age沒有初始化,不報錯.相當于屬性age被"懸掛"起來.唯一注意的是在getAge()之前如果不調用setAge()設置值,則會出現意料之外的結果---相當于隨機訪問了一塊內存地址,地址內值未初始化.
? ? ? ? 給屬性默認賦值,所有對象的屬性用同一個值,比如將上面的構造函數改成
PersonDirectSome(const string& str) :name(str),age(20){} //所有對象age默認為20
? ? ? ? 則所有對象的年齡不需要傳入,都被默認設成20.?
? ? ? ? 3>間接賦值
? ? ? ? 構造函數也表達了形參和屬性之間的一種"因果"聯系.他們不一定是賦值關系.
? ? ? ? 舉例:構造函數中有表示"姓"的字符串fname,用一個字符lname表示"名"的字符串首字母.
class PersonIndirect {string fname;char lname;int age;
public:PersonIndirect(const string& strf, const string& strl ,int ag) :fname(strf), age(ag) {lname = strl.at(0); //獲得傳入字符串的首字母,交給屬性}char getLname() { //獲得字符return lname;}
};
? ? ? ? 調用構造函數,輸入表示"姓"和"名"的字符串,生成對象.
PersonIndirect zs_i("zhang", "san",44);cout << "對象名的首字母是:" << zs_i.getLname() << endl;
默認構造函數
? ? ? ? C++提供了默認構造函數.?舉例:
class Default { //默認構造函數
private:int age;
public:int getAge() const{ return age; }
};
? ? ? ? 調用默認構造函數生成對象,什么都不用輸入
Default df; //什么都不用輸入,調用默認構造函數生成對象cout << df.getAge() << endl; //警告"使用未初始化內存",因為沒有給age賦值
? ? ? ? 如果定義了其他構造函數,默認構造函數將失效,上述代碼中Default df;將報錯
? ? ? ? 默認構造函數還是比較有用的,特別在類繼承中,派生對象的生成必須先生成基類對象,派生類的構造函數必須要給基類構造函數傳入參數.如果給基類定義默認構造函數,則可以簡化派生類構造函數.例如:
class Base { //基類定義int age;
public:Base(int ag):age(ag){} //基類普通構造函數Base() { //基類提供默認構造函數 age = 20;}int getAge() const { return age; }
};
class BasePlus : public Base { //派生類定義string name;
public:BasePlus(const string& na,int ag):Base(ag),name(na){} //派生類普通構造函數,參數傳給基類構造函數BasePlus(const string&na) :name(na) {}//派生類普通構造函數,忽略傳給基類參數,使用了基類默認構造函數
};
? ? ? ? 調用派生類構造函數,生成派生類對象
BasePlus lisi("lisi", 30); //BasePlus普通構造函數,傳入年齡30給基類構造函數cout << "李四的年齡是:" << lisi.getAge() << endl;;BasePlus zs("zs"); //由于基類中定義默認構造函數,簡化了派生類對象生成時的編碼cout << "張三的年齡是:" << zs.getAge() << endl;
?? ? ? ? 所以一般需要自己定義默認構造函數,即類的構造函數兩個以上,含自定義的默認構造函數
? ? ? ? 定義方法也比較簡單,默認給屬性賦值就可以.?
Base() { //基類提供默認構造函數 age = 20;}
============================================================BasePlus() { //派生類默認構造函數Base(20);name = "nobody";}
? ? ? ? 還有一種更為簡單的方法,給構造函數提供默認參數. 但是試了下如果多個函數使用默認參數的情況似乎不行,所以這是一種選項.? ? ? ??
Base(int ag=20):age(ag){} //基類普通構造函數,提供默認參數//Base() { //替換部分 // age = 20;//}
========================================================
小結
? ? ? ? 有時候覺得C++的語法已經夠復雜的了,像構造函數這些相對簡單的內容要不要搞得那么復雜.學會后總結一些常規用法,以后就是"復制"和"粘貼".
? ? ? ? 小結構造函數的寫法:
? ? ? ? 1>直接賦值,形參和屬性一一對應.這也是用得最多的寫法
? ? ? ? 2>建議自定義默認構造函數,不寫形參,直接給屬性賦值.
? ? ? ? 3>?默認參數,簡化函數調用