c語言入門到c++使用高手:深入學習C++之類 (二)

第三章 類

第二節 構造函數詳解, explicit, 初始化列表

1. 構造函數

  • 在類中,有一種特殊的成員函數,他的名字和類名相同,我們在創建類的對象的時候,這個特殊的成員函數就會被系統自動調用,這個成員函數就叫做"構造函數",因爲構造函數會被系統自動調用,我們可以理解構造函數的目的就是初始化類對象的數據成員

  • 特點

  1. 構造函數沒有返回值(沒有void),這也是構造函數的特殊之處

  2. 不可以手工調用構造函數,否則編譯就會出錯

  3. 正常情況下,構造函數應該被聲明爲public,因爲我們創建一個對象時,系統要替我們調用public函數,
    因爲類缺省的成員是私有成員,必須說明構造函數爲public

  4. 構造函數中如果有多個參數,則我們創建對象的時候也要帶上這些參數

  • Time.h
//
// Created by felaim on 2020/5/26.
//

#ifndef LESSION_PART_TWO_TIME_H
#define LESSION_PART_TWO_TIME_H

class Time {
private:
    // 私有成員變量不能在外部直接用成員變量名使用
    // 可以自己的成員函數調用
    int Millisecond;//毫秒
    void initMillTime(int mls);

public:
    int Hour;
    int Minute;
    int Second;
    // 成員函數
    void initTime(int tmphour, int tmpmin, int tmpsec);
public:
    //構造函數
    Time(int tmphour, int tmpmin, int tmpsec);
};

#endif //LESSION_PART_TWO_TIME_H

  • Time.cpp
//
// Created by felaim on 2020/5/26.
//
#include "Time.h"

// 成員函數initTime的實現
// ::叫做作用域運算符,表示initTime屬於Time類
void Time::initTime(int tmphour, int tmpmin, int tmpsec) {
    //成員函數中可以直接使用成員變量名
    // 哪個對象調用的成員函數,這些成員變量就屬於對應的對象
    Hour = tmphour;
    Minute = tmpmin;
    Second = tmpsec;

    initMillTime(25);
}

void Time::initMillTime(int mls) {
    Millisecond = mls; //成員函數訪問成員變量
}

// 構造函數的實現
Time::Time(int tmphour, int tmpmin, int tmpsec) {
    Hour = tmphour;
    Minute = tmpmin;
    Second = tmpsec;

    initMillTime(0);
}
  • main.cpp
#include <iostream>
#include "Time.h"

using namespace std;

int main() {
    Time myTime(11, 44, 43);
    cout << "myTime: " << myTime.Hour << ":" << myTime.Minute << ":" << myTime.Second << endl;

    Time myTime1 = Time(1, 2, 3);
    Time myTime2{1, 2, 3};
    Time myTime3 ={1, 2, 3};
    Time myTime4 = Time{1, 2, 3};
    
    return 0;
}

2. 多個構造函數

  • 一個類中可以有多個構造函數,就可以爲類對象的創建提供多種初始化方法,
    但是多個構造函數要有所區別,不能完全相同

  • Time.h

//
// Created by felaim on 2020/5/26.
//

#ifndef LESSION_PART_TWO_TIME_H
#define LESSION_PART_TWO_TIME_H

class Time {
private:
    // 私有成員變量不能在外部直接用成員變量名使用
    // 可以自己的成員函數調用
    int Millisecond;//毫秒
    void initMillTime(int mls);

public:
    int Hour;
    int Minute;
    int Second;
    // 成員函數
    void initTime(int tmphour, int tmpmin, int tmpsec);
public:
    //構造函數
    Time(int tmphour, int tmpmin, int tmpsec);

    //不加參數
    Time();
};

#endif //LESSION_PART_TWO_TIME_H

  • Time.cpp
//
// Created by felaim on 2020/5/26.
//
#include "Time.h"

// 成員函數initTime的實現
// ::叫做作用域運算符,表示initTime屬於Time類
void Time::initTime(int tmphour, int tmpmin, int tmpsec) {
    //成員函數中可以直接使用成員變量名
    // 哪個對象調用的成員函數,這些成員變量就屬於對應的對象
    Hour = tmphour;
    Minute = tmpmin;
    Second = tmpsec;

    initMillTime(25);
}

void Time::initMillTime(int mls) {
    Millisecond = mls; //成員函數訪問成員變量
}

// 構造函數的實現
Time::Time(int tmphour, int tmpmin, int tmpsec) {
    Hour = tmphour;
    Minute = tmpmin;
    Second = tmpsec;

    initMillTime(0);
}

Time::Time(){
    Hour = 12;
    Minute = 59;
    Second = 59;
}

  • main.cpp
#include <iostream>
#include "Time.h"

using namespace std;

int main() {
    Time myTime(11, 44, 43);
    cout << "myTime: " << myTime.Hour << ":" << myTime.Minute << ":" << myTime.Second << endl;
    //使用第二個構造函數
    Time myTime1;
    cout << "myTime1: " << myTime1.Hour << ":" << myTime1.Minute << ":" << myTime1.Second << endl;

    // 對象拷貝
    Time myTime2;
    // myTime3 並沒有調用傳統意義上的構造函數,而是調用的是拷貝構造函數,後續會講
    Time myTime3 = myTime2;


    return 0;
}

3. 函數默認參數

  • 規定
  1. 默認值只能放在函數聲明中,除非該函數沒有函數聲明

  2. 在具有多個參數的函數中指定默認值時,默認參數必須出現在不默認參數的右邊,一旦某個默認參數開始指定默認值,它右邊的所有參數必須指定默認值

  • Time.h
//
// Created by felaim on 2020/5/26.
//

#ifndef LESSION_PART_TWO_TIME_H
#define LESSION_PART_TWO_TIME_H

class Time {
private:
    // 私有成員變量不能在外部直接用成員變量名使用
    // 可以自己的成員函數調用
    int Millisecond;//毫秒
    void initMillTime(int mls);

public:
    int Hour;
    int Minute;
    int Second;
    // 成員函數
    void initTime(int tmphour, int tmpmin, int tmpsec);
public:
    //構造函數
    Time(int tmphour, int tmpmin, int tmpsec=22);

    //不加參數
    Time();
};

#endif //LESSION_PART_TWO_TIME_H

  • Time.cpp
//
// Created by felaim on 2020/5/26.
//
#include "Time.h"

// 成員函數initTime的實現
// ::叫做作用域運算符,表示initTime屬於Time類
void Time::initTime(int tmphour, int tmpmin, int tmpsec) {
    //成員函數中可以直接使用成員變量名
    // 哪個對象調用的成員函數,這些成員變量就屬於對應的對象
    Hour = tmphour;
    Minute = tmpmin;
    Second = tmpsec;

    initMillTime(25);
}

void Time::initMillTime(int mls) {
    Millisecond = mls; //成員函數訪問成員變量
}

// 構造函數的實現
Time::Time(int tmphour, int tmpmin, int tmpsec) {
    Hour = tmphour;
    Minute = tmpmin;
    Second = tmpsec;

    initMillTime(0);
}

Time::Time(){
    Hour = 12;
    Minute = 59;
    Second = 59;
}

  • main.cpp
#include <iostream>
#include "Time.h"

using namespace std;

int main() {
    Time myTime(11, 44, 43);
    cout << "myTime: " << myTime.Hour << ":" << myTime.Minute << ":" << myTime.Second << endl;
    //使用第二個構造函數
    Time myTime1;
    cout << "myTime1: " << myTime1.Hour << ":" << myTime1.Minute << ":" << myTime1.Second << endl;

    // 有了默認參數過後,第三個參數可以不給對應值,調用三個參數的構造函數
    Time myTime2(12,3);
    cout << "myTime2: " << myTime2.Hour << ":" << myTime2.Minute << ":" << myTime2.Second << endl;
    
    return 0;
}

4. 隱式轉換和explicit

隱式轉換

  • Time.h
//
// Created by felaim on 2020/5/26.
//

#ifndef LESSION_PART_TWO_TIME_H
#define LESSION_PART_TWO_TIME_H

class Time {
private:
    // 私有成員變量不能在外部直接用成員變量名使用
    // 可以自己的成員函數調用
    int Millisecond;//毫秒
    void initMillTime(int mls);

public:
    int Hour;
    int Minute;
    int Second;
    // 成員函數
    void initTime(int tmphour, int tmpmin, int tmpsec);
public:
    //構造函數
    Time(int tmphour, int tmpmin, int tmpsec=22);

    //不加參數
    Time();

    //單參數的構造函數
    Time(int tmphour);
};

#endif //LESSION_PART_TWO_TIME_H

  • Time.cpp
//
// Created by felaim on 2020/5/26.
//
#include "Time.h"

// 成員函數initTime的實現
// ::叫做作用域運算符,表示initTime屬於Time類
void Time::initTime(int tmphour, int tmpmin, int tmpsec) {
    //成員函數中可以直接使用成員變量名
    // 哪個對象調用的成員函數,這些成員變量就屬於對應的對象
    Hour = tmphour;
    Minute = tmpmin;
    Second = tmpsec;

    initMillTime(25);
}

void Time::initMillTime(int mls) {
    Millisecond = mls; //成員函數訪問成員變量
}

// 構造函數的實現
Time::Time(int tmphour, int tmpmin, int tmpsec) {
    Hour = tmphour;
    Minute = tmpmin;
    Second = tmpsec;

    initMillTime(0);
}

Time::Time(){
    Hour = 12;
    Minute = 59;
    Second = 59;
}

Time::Time(int tmphour){
    Hour = tmphour;
    Minute = 59;
    Second = 59;
}


  • main.cpp
#include <iostream>
#include "Time.h"

using namespace std;

void func(Time time1) {
    cout << "time1: " << time1.Hour << ":" << time1.Minute << ":" << time1.Second << endl;
    return;
}

int main() {
    //可以理解
    Time myTime = {12};
    //編譯系統把數字轉換成了Time類型的轉換,存在臨時對象隱式轉換
    Time myTime1 = 1;
    cout << "myTime1: " << myTime1.Hour << ":" << myTime1.Minute << ":" << myTime1.Second << endl;

    Time myTime2 = (1, 3, 4, 5, 6);
    cout << "myTime2: " << myTime2.Hour << ":" << myTime2.Minute << ":" << myTime2.Second << endl;

    // 4被轉換成了Time臨時的對象,調用了單參數的構造函數
    func(4);

    return 0;
}

explicit

  • 能否強制系統,構造函數不能做隱式類型轉換?
    如果構造函數聲明中explict,則這個構造函數只能用於初始化和顯式類型轉換

  • 修改Time.h中的單參數函數聲明

//單參數的構造函數
    explicit Time(int tmphour);
  • main.cpp中測試,不允許隱式類型轉換
#include <iostream>
#include "Time.h"

using namespace std;

void func(Time time1) {
    cout << "time1: " << time1.Hour << ":" << time1.Minute << ":" << time1.Second << endl;
    return;
}

int main() {
    // 添加explict仍然可行
    Time myTime{12};
    cout << "myTime: " << myTime.Hour << ":" << myTime.Minute << ":" << myTime.Second << endl;

    // 添加explict不可行
    //Time myTime1 = 12;
    //顯式類型轉換後可行
    Time myTime1 = Time(8);
    cout << "myTime1: " << myTime1.Hour << ":" << myTime1.Minute << ":" << myTime1.Second << endl;
    
    // 4被轉換成了Time臨時的對象,調用了單參數的構造函數
    // 進行顯式類型轉換
    func(Time(4));

    return 0;
}
  • 對於單參數的構造函數,一般都聲明稱爲explicit,使得類構造更加合理一些

5. 構造函數初始化列表

  • 將Time.cpp中原來三參數的構造函數寫成如下的形式,即使用了構造函數初始化列表
Time::Time(int tmphour, int tmpmin, int tmpsec)
        : Hour(tmphour), Minute(tmpmin), Second(tmpsec), Millisecond(0) {}
  • 這種寫法顯得比較高大上,顯得專業

  • 效率上會更高一些

關於c語言入門到c++使用高手的完整章節在這篇博客中,建議收藏!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章