【C++】c++中的六個預設函式——建構函式
類的6個預設的成員函式包括:
建構函式、解構函式、拷貝建構函式、賦值運算子過載函式、取地址操作符過載、const修飾的取地址操作符過載。(但是重點講前四個)
- 建構函式(可以過載)
在C++中,有一種特殊的成員函式,它的名字和類名相同,沒有返回值,不需要使用者顯式呼叫(使用者也不能手動呼叫),而是在建立物件時自動執行。這種特殊的成員函式就是建構函式(Constructor)。
class Student{ private: char *m_name; int m_age; float m_score; public: //宣告建構函式 Student(char *name, int age, float score); //宣告普通成員函式 void show(); }; //定義建構函式 Student::Student(char *name, int age, float score){ m_name = name; m_age = age; m_score = score; } //定義普通成員函式 void Student::show(){ cout<<m_name<<"的年齡是"<<m_age<<",成績是"<<m_score<<endl; } int main(){ //建立物件時向建構函式傳參 Student stu("Li", 15, 92.5f); stu.show(); //建立物件時向建構函式傳參 Student *pstu = new Student("Hua", 16, 96); pstu -> show(); return 0; }
Student 類中定義了一個建構函式Student( ),它的作用是給三個 private 屬性的成員變數賦值。要想呼叫該建構函式,就得在建立物件的同時傳遞實參,並且實參由( )包圍,和普通的函式呼叫非常類似。
- 建構函式的過載
和普通成員函式一樣,建構函式是允許過載的。一個類可以有多個過載的建構函式,建立物件時根據傳遞的實參來判斷呼叫哪一個建構函式。建構函式的呼叫是強制性的,一旦在類中定義了建構函式,那麼建立物件時就一定要呼叫,不呼叫是錯誤的。如果有多個過載的建構函式,那麼建立物件時提供的實參必須和其中的一個建構函式匹配;反過來說,建立物件時只有一個建構函式會被呼叫
#include <iostream> #include <string> using namespace std; class Student{ private: char *m_name; int m_age; float m_score; public: //宣告建構函式 Student(char *name, int age, float score); //宣告 Student(); //宣告普通成員函式 void show(); void setname(char *name); void setage(int age); void setscore(float score); }; //定義建構函式 Student::Student(char *name, int age, float score){ m_name = name; m_age = age; m_score = score; } //建構函式的過載 Student::Student() { m_name = NULL; m_age = 0; m_score = 0.0; } void Student::setname(char *name) { m_name = new char[strlen(name) + 1](); strcpy_s(m_name, strlen(name) + 1, name);//用strcpy_s (oldstr, len, newstr)似乎更安全 } void Student::setage(int age){ m_age = age; } void Student::setscore(float score){ m_score = score; } //定義普通成員函式 void Student::show(){ cout<<m_name<<"的年齡是"<<m_age<<",成績是"<<m_score<<endl; } int main(){ //建立物件時向建構函式傳參 Student stu("Ming", 15, 92.5f); stu.show(); //建立物件時向建構函式傳參 Student *pstu = new Student(); //pstu -> show(); pstu -> setname("Hua"); pstu -> setage(16); pstu -> setscore(96.7f); pstu -> show(); }
建構函式Student()將各個成員變數的值設定為空,它們是過載關係。根據Student()建立物件時不會賦予成員變數有效值,所以還要呼叫成員函式 setname()、setage()、setscore() 來給它們重新賦值。
- 預設建構函式(是一個淺拷貝)
如果使用者自己沒有定義建構函式,那麼編譯器會自動生成一個預設的建構函式,只是這個建構函式的函式體是空的,也沒有形參,也不執行任何操作。比如上面的 Student 類,預設生成的建構函式如下: Student(){ }
一個類必須有建構函式,要麼使用者自己定義,要麼編譯器自動生成。一旦使用者自己定義了建構函式,不管有幾個,也不管形參如何,編譯器都不再自動生成。
最後需要注意的一點是,呼叫沒有引數的建構函式也可以省略括號。在棧上建立物件可以寫作Student stu()或Student stu,在堆上建立物件可以寫作Student *pstu = new Student()或Student *pstu = new Student,它們都會呼叫建構函式 Student()。
- 引數初始化列表
-
-
定義建構函式時並沒有在函式體中對成員變數一一賦值,其函式體為空(當然也可以有其他語句),而是在函式首部與函式體之間添加了一個冒號: 後面緊跟m_name(name), m_age(age), m_score(score)語句,這個語句的意思相當於函式體內部的m_name = name; m_age = age; m_score = score;語句,也是賦值的意思。
-
//引數初始化表 Student::Student(char *name, int age, float score): m_name (name), m_age (age), m_score (score){ }
注意,引數初始化順序與初始化表列出的變數的順序無關,它只與成員變數在類中宣告的順序有關。
#include <iostream>
using namespace std;
class Fun{
private:
int m_a;
int m_b;
/*
改為:
int m_b;
int m_a; 輸出就會是使用者想得到的數值
*/
public:
Fun(int b);
void show();
};
Fun::Fun(int b): m_b(b), m_a(m_b){ //呼叫順序只和Fun類中宣告的順序有關
}
void Fun::show(){ cout<<m_a<<", "<<m_b<<endl; }
int main(){
Fun re(100);
re.show();
return 0;
}
- 初始化 const 成員變數
初始化 const 成員變數的唯一方法就是使用引數初始化表,例如下面的例子:
#include <iostream>
using namespace std;
class Fun{
private:
const int m_a;//初始化 const 成員變數
int m_b;
public:
Fun(int b);
void show();
};
Fun::Fun(int b): m_a(b){
m_b = b;
}
void Fun::show(){ cout<<m_a<<", "<<m_b<<endl; }
int main(){
Fun re(100);
re.show();
return 0;
}