1. 程式人生 > >C++知識點---類和物件

C++知識點---類和物件

1. 類和物件

  • 類:和結構體類似,存在資料(變數),還有方法(函式),即類包含成員變數和成員函式

  • 物件:類的例項,將物件作為程式的基本單元,將程式和資料封裝其中,以提高軟體的重用性、靈活性和擴充套件性。

2. 類和物件的特點

  • 類:具有封裝性,將變數和函式封裝到類當中,類的訪問限定符(public、private、protected)體現了面向物件的封裝性

  • 物件:封裝,繼承,多型

3. 具體例子

3.1 類的定義

//類內定義成員函式
class Person
{
public:
    void Show()//可以直接從類外部訪問,作用域為:到下一個public,或者類結束
{ cout<<_name<<endl; cout<<_sex<<endl; cout<<_age<<endl; } private://不可直接從類外部訪問 char* _name; char* _sex; int _age; } //類外定義成員函式 class Person { public: void Show();//可以直接從類外部訪問,作用域為:到下一個public,或者類結束 private://不可直接從類外部訪問 char
* _name; char* _sex; int _age; } void Date::Show()//類外寫成員函式必須指明函式屬於哪一個類域 { cout<<_name<<endl; cout<<_sex<<endl; cout<<_age<<endl; }

3.2 例項化:

class Person
{
public:
    void Show()
    {
        cout<<_name<<endl;
        cout<<_sex<<endl;
        cout
<<_age<<endl; } private: char* _name; char* _sex; int _age; } void Test() { Person P;//類的物件 p._name = "張三"; P._sex = "男"; P._age = 10; }

4. 類的作用域:

  • 成員函式和成員變數都在類的作用域內,類內部成員可直接訪問

  • 類外定義成員,使用::表示在哪個作用域

例:

//類的宣告
class Person
{
Public:
    void show();
privatechar* _name;
    int _age;
}

//定義
Person::show()
{
    cout<<_name<<endl;
    cout<<_age<<endl;
}

5. 類的大小:

  • 和結構體記憶體對齊規則一致

  • 只取決於成員變數的大小,成員函式不佔物件空間(原因:將成員函式放在公共程式碼區,供大家使用)

  • 空類的大小為1,開闢一個空間表示類的存在

  • 記憶體對齊規則

  • 第一個成員在與結構體變數偏移量為0的地址處。
  • 其他成員變數要對齊到某個數字(對齊數)的整數倍的地址處。
    對齊數 = 編譯器預設的一個對齊數 與 該成員大小的較小值。
    VS中預設的值為8
    Linux中的預設值為4
  • 結構體總大小為最大對齊數(每個成員變數除了第一個成員都有一個對齊數)的整數倍。
  • 如果嵌套了結構體的情況,巢狀的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數(含巢狀結構體的對齊數)的整數倍。

6. 記憶體對齊的原因

  • 由於存在記憶體訪問機制,每次訪問記憶體時從0號地址處連續讀取4位元組(或4位元組的整數倍);

  • 如果不存在記憶體對齊,讀取一個變數時會讀取兩次或者三次甚至更多,反而降低效率

  • 記憶體對齊的前提下,讀取一次即可提高效率

7. this指標

  • 每個成員函式都有一個指標形參,它的名字是固定的,稱為this指標,this指標是隱式的。(建構函式比較特殊,沒有這個隱含this形參)

  • 編譯器會對成員函式進行處理,在物件呼叫成員函式時,物件地址作實參傳遞給成員函式的第一個形參this指標。

  • this指標是成員函式隱含指標形參,是編譯器自己處理的,我們不能在成員函式的形參中新增this指標的引數定義,也不能在呼叫時
    顯示傳遞物件的地址給this指標。
    類的

void show();//原本成員函式

void show(Date* this);//編譯器處理的成員函式

8. 預設成員函式

8.1 建構函式
  • 沒有返回值,可以有引數,沒有引數的建構函式被認為是預設建構函式,但預設建構函式只允許有一個

  • 與類同名,可以有多個建構函式 ,可以過載, 沒有隱含的this形參

  • 作用是將物件初始化,創造出物件時系統自動呼叫建構函式進行物件的例項化

例:

class Date
{
public:

//兩個預設引數只可取其一

    Date();//(1)類內宣告


    /*Date(int year=1900,int month=1,int day=1)//(2)類內定義
    {
        _year=year;
        _month=month;
        _day=day;
    }*/

    void show()
    {
        cout<<_year<<endl;
        cout<<_month<<endl;
        cout<<_day<<endl;
    }
private:
    int _month;
    int _year;
    int _day;
}

//類外定義:
Date::Date()
{
    _year=1900;
    _month=1;
    _day=1;
}

注意:如果沒有定義建構函式,編譯器會自己生成預設預設建構函式(無參的建構函式),如果是成員變數是內建型別,預設建構函式不會初始化,如果成員變數是自定義型別,自動生成的預設建構函式呼叫自定義型別的建構函式進行初始化

例:

//自定義型別
class Time
{
public:
    Time()//自定義型別的建構函式
    {
        cout<<_hour<<endl;
    }
private:
    int _hour;
}
class Date
{
public://無建構函式,生成預設的預設建構函式(無參的建構函式),什麼也不做(成員函式有自定義型別除外)
    void show()
    {
        cout<<_year<<endl;
        cout<<_month<<endl;
        cout<<_day<<endl;
    }
private:
    int _month;
    int _year;
    int _day;//預設生成的建構函式不會對齊初始化
    Time _t;//呼叫自定義型別的建構函式對其進行初始化
}


8. 2 解構函式
  • 與類同名,並且與建構函式工作性質相反,故有~ 標識解構函式

  • 當物件生命週期結束(即出了類的作用域),系統自動呼叫解構函式

  • 不支援過載,完成清理工作(動態開闢),保證物件的初始化和銷燬

例:

class SeqList
{
public:
    SeqList(size_t  capacity=0)//建構函式
    {
        if(capacity > 0)
        {
            _a=(int*)malloc(sizeof(int)*capacity);
            _capacity=capacity;
            _size=0;
        }
        else
        {
            _a=NULL;
            _capacity=_size=0
        }

    }

    ~SeqList()//解構函式
    {
        free(_a);
        _size=_capacity=0;
    }

private:
    int*  _a;
    size_t _size;
    size_t _capacity;

}
8.3 拷貝建構函式
  • 引數是一個同類型的物件,使用同類物件進行初始化

  • 拷貝建構函式使用引用

  • 如果沒有定義拷貝建構函式,系統自動生成預設拷貝建構函式並進行初始化

例:

class Date
{
public:

    Date(int year=1900,int month=1,int day=1)//預設引數
    {
        _year=year;
        _month=month;
        _day=day;
    }

    Date(const Date& d)//加引用,防止無限遞迴
    {
        _year=d._year;
        _month=d._month;
        _day=d._day;
    }
    void show()
    {
        cout<<_year<<endl;
        cout<<_month<<endl;
        cout<<_day<<endl;
    }
private:
    int _month;
    int _year;
    int _day;
}
8.4 運算子過載
  • 作用:增強程式碼的可讀性

  • 特徵:operator + 運算子(例:operator<)

  • 不能過載的運算子: .* :: sizeof ?: :

  • 兩種形態:成員函式(一個引數,還有一個隱含的this),全域性

例:

class Date
{
public:

    Date(int year=1900,int month=1,int day=1);//預設引數
    Date(const Date& d);//加引用,防止無限遞迴
    void show();
    bool operator==(const Date& d1,const Date& d2);//類內宣告
private:
    int _month;
    int _year;
    int _day;
}

//全域性
bool Date::operator==(const Date& d1,const Date& d2)
{
    return d1._year==d2._year 
        && d1._month==d2.month
        && d1._day==d2._day;
}


//成員函式

class Date
{
public:

    Date(int year=1900,int month=1,int day=1);//預設引數
    Date(const Date& d);//加引用,防止無限遞迴
    void show();
    bool operator==(const Date& d1,const Date& d2);//成員函式
    {
        return d1._year==d2._year
            && d1._month==d2.month
            && d1._day==d2.day;
    }
private:
    int _month;
    int _year;
    int _day;
}