類和對象

1. 類和對象

1.1 聲明類

類包含:屬性(數(shù)據(jù)),方法(類成員的函數(shù))
使用關(guān)鍵字class聲明,如聲明一個(gè)人類

//使用關(guān)鍵字class聲明一個(gè)人類
class Human
{
    //數(shù)據(jù)屬性 data attributes
    string Name;
    string DateOfBirth;
    string PlacwOfBirth;

    //方法 method
    void Talk(string TextToTalk);
    void IntroduceSelf();
}

1.2 實(shí)例化對象

實(shí)例化對象的語法:

//實(shí)例化對象
Human Tom;    //在棧上實(shí)例化一個(gè)對象
Human *pAHuman = new Human();        //在堆上實(shí)例化一個(gè)對象
delete pAHuman;        //刪除對象

1.3 使用句點(diǎn)運(yùn)算符訪問類成員

//使用句點(diǎn)運(yùn)算符訪問類成員
// 訪問類成員數(shù)據(jù)和類成員函數(shù)
Human Tom;
Tom.DateOfBirth="1990";
Tom.IntroduceSelf;
//指針pTom形式
Human* pTom = new Human();
(*pTom).IntroduceSelf();

1.4 使用指針運(yùn)算符(->)訪問成員

//使用指針運(yùn)算符(->)訪問成員
//Human Tom;
//Human *Ptom = &Tom;
Human* pTom = new Human();
pTom->DataOfBirth = "1970";
pTom->IntroduceSelf();

2. 關(guān)鍵字public和private

public和private兩個(gè)關(guān)鍵字能夠控制類書香的訪問和操縱方式。一般而言,需要用private修飾類成員數(shù)據(jù),以保護(hù)數(shù)據(jù)不被暴力修改。面向?qū)ο缶幊讨行薷膶ο蟮臄?shù)據(jù)需要優(yōu)雅地使用類成員方法對數(shù)據(jù)進(jìn)行修改。

//一個(gè)包含private和public修飾的類
class Human
{
private:
    //私有成員數(shù)據(jù)
    int Age;
    string name;
public:
    int GetAge()
    {
         return Age;
    }
    int SetAge(int InputAge)
    {
        Age = InputAge;
    }
//...其他成員...
};

2.1 private關(guān)鍵字實(shí)現(xiàn)數(shù)據(jù)抽象

private關(guān)鍵字的特點(diǎn):private指定了不能從類外訪問的信息(成員數(shù)據(jù)和成員函數(shù)),對外界隱藏類使用者無需知道的東西

#include<iostream>
using namespace std;
class Human
{
private:
    //private member data
    int Age;
public:
    void SetAge(int InputAge)
    {
        Age = InputAge;
    }
    int GetAge()
    {
        if(Age > 30)
        return (Age - 2);
        else
            return Age;
    }
};

int main()
{
    Human FirstMan;
    FirstMan.SetAge(45);
    
    Human FirstWoman;
    FirstWoman.SetAge(23);
    
    cout << "Age of FirstMan "<< FirstMan.GetAge() <<endl;
    cout << "Age of FirstWoman " << FirstWoman.GetAge() <<endl;
    return 0;
}

3. 構(gòu)造函數(shù)

構(gòu)造函數(shù)是一種特殊的方法,在創(chuàng)建對象時(shí)使用。和普通的函數(shù)一樣,可以被重載。

3.1 聲明和實(shí)現(xiàn)構(gòu)造函數(shù)

構(gòu)造函數(shù)的名稱和類名相同

//聲明構(gòu)造函數(shù)
class Human
{
public:
    Human()
    {
        // 構(gòu)造函數(shù)的代碼
    }
};

//在類外定義構(gòu)造函數(shù)
class Human
{
public:
    Human();
};
//類外提供構(gòu)造函數(shù)的實(shí)現(xiàn)
Human::Human()
{
    //構(gòu)造函數(shù)的代碼
}

3.2 何時(shí)使用構(gòu)造函數(shù)

構(gòu)造函數(shù)在創(chuàng)建對象時(shí)被調(diào)用,構(gòu)造函數(shù)可將成員變量(int, string, 指針)初始化為已知值。

3.3 重載構(gòu)造函數(shù)

構(gòu)造函數(shù)可以被重載
可以選擇不實(shí)現(xiàn)默認(rèn)構(gòu)造函數(shù),從而要求實(shí)例化對象時(shí)必須提供某些參數(shù),以使用重載的構(gòu)造函數(shù)。

//重載構(gòu)造函數(shù)
class Human
{
public:
    Human()
    {
        //默認(rèn)構(gòu)造函數(shù)
    }
    Human(string HumansName)
    {
        //重載構(gòu)造函數(shù)
    }
};

3.4 沒有默認(rèn)構(gòu)造函數(shù)的類

如果沒有默認(rèn)構(gòu)造函數(shù),而提供重載的構(gòu)造函數(shù)時(shí),編譯器不會(huì)生產(chǎn)默認(rèn)構(gòu)造函數(shù)。
這樣可以使創(chuàng)建每個(gè)對象時(shí),都必須提供某些對象的參數(shù)。

3.5 帶默認(rèn)值的構(gòu)造函數(shù)參數(shù)

//帶默認(rèn)值的構(gòu)造函數(shù)參數(shù)
class Human
{
private:
    string Name;
    int Age;
public:
    // 重載構(gòu)造函數(shù)
    Human(string HumansName, int HumansAge = 25)
    {
        Name = HumansName;
        Age = HumansAge;
        cout << "overload constructor creates " << Name;
        cout << " of age " << Age <<endl;
    }
    // other members
};

3.6 包含初始化列表的構(gòu)造函數(shù)

//包含初始化列表的構(gòu)造函數(shù)
class Human
{
private:
    string Name;
    int Age;
public:
    Human(string InputName, int InputAge):Name(InputName),Age(InputAge)
    {
        cout << "Constructor with parameters: ";
        cout << "Human " << Name <<", "<< Age << " years old"<<endl;
    }
};

4. 析構(gòu)函數(shù)

析構(gòu)函數(shù)和構(gòu)造函數(shù)一樣,也是一種特殊的函數(shù)。析構(gòu)函數(shù)在對象銷毀時(shí)自動(dòng)被調(diào)用。
析構(gòu)函數(shù)不能被重載。
如果忘記實(shí)現(xiàn)析構(gòu)函數(shù),則編譯器會(huì)自動(dòng)生成一個(gè)偽(dummy)析構(gòu)函數(shù)并調(diào)用它,偽析構(gòu)函數(shù)為空,不會(huì)釋放動(dòng)態(tài)分配的內(nèi)存。

4.1 聲明和實(shí)現(xiàn)析構(gòu)函數(shù)

析構(gòu)函數(shù)的聲明

//析構(gòu)函數(shù)的聲明
class Human
{
public:
    ~Human()
    {
        //銷毀成員數(shù)據(jù)的代碼
    }
};

4.2 何時(shí)使用析構(gòu)函數(shù)

當(dāng)對象不在作用域或通過delete刪除時(shí),將調(diào)用析構(gòu)函數(shù)對其進(jìn)行銷毀。析構(gòu)函數(shù)成為了重置變量和釋放內(nèi)存的一種有效手段。

//用類封裝一個(gè)c風(fēng)格的字符串
#include<iostream>
using namespace std;

class MyString
{
private:
    char* Buffer;
public:
    // constructor
    MyString(const char* InitialInput)
    {
        if(InitialInput != NULL)
        {
            Buffer = new char [strlen(InitialInput)+1];
            strcpy(Buffer,InitialInput);
        }
        else
            Buffer = NULL;
    }
    // distructor
    ~MyString()
    {
        cout << "Invoking destructor, cleaning up! "<<endl;
        if(Buffer != NULL)
        {
            delete[] Buffer;
        }
    }
    int GetLength()
    {
        return strlen(Buffer);
    }
    
    const char* GetString()
    {
        return Buffer;
    }
};

int main()
{
    MyString SayHello("hello from string class");
    cout << "Length: " << SayHello.GetLength() << endl;
    cout << "content: " << SayHello.GetString() << endl;
    return 0;
}

5. 復(fù)制構(gòu)造函數(shù)

調(diào)用函數(shù)時(shí),如果函數(shù)的形參是對象,則傳遞的實(shí)參對象也被復(fù)制,因此需要復(fù)制構(gòu)造函數(shù)。

5.1 淺復(fù)制存在的問題

淺復(fù)制是指在傳遞對象時(shí),參數(shù)被復(fù)制過程中僅復(fù)制了指向內(nèi)存的指針變量,而沒有復(fù)制包含內(nèi)容的內(nèi)存塊。


image.png

被淺復(fù)制的對象在某個(gè)函數(shù)中脫離作用域時(shí)就被析構(gòu),然而主調(diào)函數(shù)中往往還要對其進(jìn)行一次析構(gòu),這就出現(xiàn)了問題。

5.2 使用復(fù)制構(gòu)造函數(shù)確保深復(fù)制

聲明構(gòu)造函數(shù)的語法:

//拷貝構(gòu)造函數(shù)的實(shí)現(xiàn)
class MyString
{
    Mystring const(const MyString& CopySource);
};
MyString::MyStrin(const MyString& CopySource)
{
    //拷貝構(gòu)造函數(shù)實(shí)現(xiàn)代碼
};

注意!

  1. 類包含原始指針成員時(shí),必須要變細(xì)人復(fù)制構(gòu)造函數(shù)和復(fù)制賦值運(yùn)算符;
  2. 編寫復(fù)制構(gòu)造函數(shù)時(shí),必須要將接受原對象的參數(shù)聲明為const引用;
  3. 必須將類成員聲明為std:string和智能指針類(而非原始指針),因?yàn)樗麄儗?shí)現(xiàn)了復(fù)制構(gòu)造函數(shù),可以減少工作量;
  4. 除非萬不得已,不要將類成員聲明為原始指針;

5.3 C++11中的移動(dòng)構(gòu)造函數(shù)

如果遇到構(gòu)造函數(shù)被連續(xù)調(diào)用兩次的情況,實(shí)際上是不需要將一個(gè)對象反復(fù)構(gòu)造兩次的,此時(shí)應(yīng)該使用移動(dòng)復(fù)制構(gòu)造函數(shù)
使用移動(dòng)復(fù)制構(gòu)造函數(shù)時(shí),C++11編譯器會(huì)自動(dòng)使用它“移動(dòng)”臨時(shí)資源,避免深復(fù)制。

//拷貝構(gòu)造函數(shù)被連續(xù)調(diào)用兩次的情況
class MyString
{
    //...
};
MyString Copy(MyString& Source)    //復(fù)制string對象的函數(shù)
{
    MyString CopyForReturn(Source.GetString);
    return CopyForReturn;
}
int main()
{
    MyString sayHello("hello!");
    MyString sayHelloAgain(Copy(sayHello)); //執(zhí)行兩次拷貝構(gòu)造函數(shù),一次copy返回,一次是作為參數(shù)傳入
    return 0;
}

//移動(dòng)復(fù)制構(gòu)造函數(shù)的聲明
MyString(MyString&& MoveSource)
{
    if(MoveSource.Buffer != NULL)
    {
        Buffer = MoveSource.Buffer;
        MoveSource.Buffer = NULL;
    }
}

6. 構(gòu)造函數(shù)和析構(gòu)函數(shù)的其他用途

6.1 不允許復(fù)制的類(單例模式)

用private修飾所有的構(gòu)造函數(shù)(默認(rèn)構(gòu)造函數(shù),復(fù)制構(gòu)造函數(shù)...)
用static修飾一個(gè)函數(shù),這個(gè)函數(shù)中實(shí)例化了一個(gè)對象。從而使得該類中僅存在這一個(gè)對象。

注意:

  1. 關(guān)鍵字static用于累的數(shù)據(jù)成員時(shí),該數(shù)據(jù)成員將在所有的實(shí)例中共享
  2. 將static用于函數(shù)中聲明的局部變量時(shí),該變量的值將在兩次調(diào)用之間保持不變
  3. 將static用于成員函數(shù)時(shí),該方法將在所有實(shí)例之間共享

6.3禁止在棧中實(shí)例化的類

如果要編寫一個(gè)數(shù)據(jù)庫類,且內(nèi)部結(jié)構(gòu)超過1GB,那么就應(yīng)該禁止在棧上實(shí)例化該類,棧的空間沒有那么大。
關(guān)鍵在于兩點(diǎn):

  1. 在棧上實(shí)例化對象時(shí),將類的析構(gòu)函數(shù)用private進(jìn)行修飾,從而使得每次對象脫離作用域時(shí),無法調(diào)用析構(gòu)函數(shù),編譯器會(huì)檢查該錯(cuò)誤;而當(dāng)在堆上實(shí)例化對象時(shí),這種方法編譯器不會(huì)報(bào)錯(cuò),而導(dǎo)致內(nèi)存泄露。
  2. 需要提供一個(gè)用來銷毀實(shí)例的靜態(tài)公有函數(shù),只有這個(gè)類成員函數(shù)才能夠調(diào)用析構(gòu)函數(shù)。

7. this指針

  1. 在類中,this指針包含當(dāng)前對象的地址
  2. 靜態(tài)成員方法不會(huì)傳遞this指針,因?yàn)殪o態(tài)方法與實(shí)例不關(guān)聯(lián),由所有實(shí)例共享

8. sizeof()用于類

sizeof()是一個(gè)運(yùn)算符,用于確定指定類型需要多少內(nèi)存。
類實(shí)例化為對象后所占的內(nèi)存實(shí)際上是在設(shè)計(jì)類時(shí)就確定了,與結(jié)構(gòu)體類似,也有內(nèi)存對齊的要求。
類對象所占的內(nèi)存由類的數(shù)據(jù)成員決定。如int, bool, char* 等。

9. 結(jié)構(gòu)體和類的區(qū)別

除非指定,類的成員默認(rèn)為私有的,結(jié)構(gòu)體的成員默認(rèn)為公有的。

10. 聲明友元

聲明友元函數(shù)和友元類時(shí),則友元類和友元函數(shù)可以從類外訪問類的私有數(shù)據(jù)成員和方法。
友元函數(shù)的聲明

//友元函數(shù)的聲明
private:
    //...
    friend void function();
    //...
//友元類的聲明
//...
private:
    friend class Human;
//...
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容