1. 程式人生 > >【C++】c++中的六個預設函式——建構函式

【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;
}