1. 程式人生 > >類和物件 , 四個預設成員函式及運算子過載 , 隱含的this指標

類和物件 , 四個預設成員函式及運算子過載 , 隱含的this指標

C++入門知識(2):

1:類和物件:

類(class):

類的定義:類(class)實際上是一種高度抽象化的東西,百度上對類的定義是:類的實質是一種資料型別,類似於int、char等基本型別,不同的是它是一種複雜的資料型別。因為它的本質是型別,而不是資料,所以不存在於記憶體中,不能被直接操作,只有被例項化為物件時,才會變得可操作。簡單來說:它們是一些具有共同特徵的事物的集合。類是具有相同屬性和服務的一組物件的集合。
例如,我們可以定義一個學生類:

class 
{
public :
    void print()
    {
        cout<<"hehe"
<<endl; } private: int age; char* name; char* sex; };

類裡面包括,成員變數和成員函式。

面向物件的三大特徵:封裝,繼承,多型。

封裝是面向物件程式設計的一個重要原則。它有兩方面涵義,第一個涵義是,把物件的全部屬性和全部服務結合在一起,形成一個不可分割的獨立單位(物件)。第二個涵義也稱做“資訊隱蔽”,即儘可能隱蔽物件的內部細節,對外形成一個邊界,保留有限的介面使之與外界發生聯絡。
用比較簡潔的語言給出封裝的定義:封裝就是把物件的屬性和服務結合成一個獨立系統單位,並儘可能的隱藏物件的內部細節。
繼承和多型會在以後的部落格中進行解釋。

類有三種基本的訪問限定符:
(1)公有成員訪問限定符(public):既可以被本類中的成員函式訪問,也可以被類的作用域外的其他函式和類訪問。
(2)私有成員訪問限定符(private):成員只能被該類中的成員函式訪問,類外的其他函式則不能(友元類除外)
(3)保護成員訪問限定符(protected):成員只能被該類的成員函式或派生類的成員函式訪問。
它們的作用域都是從該訪問限定符出現的位置開始直到下一個訪問限定符出現時為止
類的預設訪問限定符是private。

物件:

前面說過,類是很多具有相同屬性和服務的物件的集合,換而言之,物件是類的例項化
一個類可以例項化很多物件。
物件的大小是類中所有成員變數的大小之和,不是單純的相加,這裡遵循記憶體對齊

原則。

#include <iostream>

using namespace std;
class Date
{
public:
    Date(int year,int month,int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d(2017,6,30);
    return 0;
}

上面這個程式裡的 d 就是Date類的一個例項化物件。

四個預設成員函式及運算子過載

C++裡一共有六個預設成員函式,這裡介紹一下四個比較常用的預設成員函式。
預設成員函式:
(1):建構函式
建構函式時用來初始化一個物件的,當物件被建立時, 建構函式自動被呼叫。其名字與類名相同,在物件的生命週期內呼叫且只調用一次,以保證每個資料成員都有一個合適的初始值。
特點
(1):建構函式的函式名類名相同;
(2):無返回值;
(3):支援過載,可以自己定義建構函式,實參決定了呼叫哪個建構函式;
(4):實際上在執行建構函式裡面的內容時,會先執行初始化列表;
(5):建構函式只在建立物件時有用,一個物件只能呼叫一次;
(6):如果不自己顯示定義建構函式,那麼編譯器會提供一個無參的預設建構函式;
(7):預設建構函式只能有一個;

例如下面這個例子,我們自己定義了一個建構函式:

#include <iostream>

using namespace std;
class Date
{
public:
    Date(int year,int month,int day)//建構函式
    {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d(2017,6,30);
    return 0;
}

拷貝建構函式
拷貝建構函式與建構函式是過載關係;函式的返回值和函式名都和建構函式的相同,唯一不同的就是引數,拷貝構造的引數是一個已經存在的物件。引數常用 const 修飾。拷貝建構函式是特殊的建構函式,建立物件時使用已存在的同類物件來進行初始化。

例如:

class Date
{
public:
    Date(int year,int month,int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    Date(const Date& date)//一定要寫成引用
    {
        _year = date._year;
        _month = date._month;
        _day = date._day;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d1(2017,6,30);
    Date d2(d1);//用已經存在的物件d1來初始化d2物件;
    return 0;
}

*注意:拷貝建構函式的形參一定要寫成引用,不然程式會崩潰,因為它會不斷呼叫拷貝建構函式,會造成死迴圈。*

如果函式的引數是傳值方式或者函式有返回值,都會去呼叫拷貝建構函式。

解構函式
在一個物件的生命週期結束時,也就是這個物件被銷燬時,解構函式會完成一些清理工作。

特點
(1):函式名是 ~類名,無引數,無返回值;
(2):物件生命週期結束時,C++編譯系統系統自動呼叫解構函式。
(3): 如果不顯示定義,編譯器會生成一個預設的解構函式。

#include <iostream>

using namespace std;
class A
{
public:
    ~A()
    {
        cout<<"hehe"<<endl;
    }
    A(int a)
    {
        _a = a;
    }
private:
    int _a;
};
int main()
{
    A a(1);
    return 0;
}

該程式它會輸出一句 hehe ,因為呼叫了解構函式。

賦值運算子的過載:

#include <iostream>

using namespace std;
class A
{
public:
    A(int a)
    {
        _a = a;
    }
    A operator=(const A& B)
    {
        _a =  B._a;
        return *this;
    }
private:
    int _a;
};
int main()
{
    A a(1);
    A b(2);
    a = b;//將b賦給a
    return 0;
}  

用於物件之間的賦值;operator是運算子過載的一個關鍵字。

隱含的this指標

this作用域是在類內部,當在類的非靜態成員函式中訪問類的非靜態成員的時候,編譯器會自動將物件本身的地址作為一個隱含引數傳遞給函式。也就是說,即使你沒有寫上this指標,編譯器在編譯的時候也是加上this的,它作為非靜態成員函式的隱含形參,對各成員的訪問均通過this進行。
this指標指向當前物件;

例如:

#include <iostream>

using namespace std;
class Date
{
public:
    Date(int year,int month,int day)//建構函式
    {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d(2017,6,30);
    return 0;
}

這個程式中,在呼叫建構函式時,會傳一個this指標,該指標指向當前的物件。直觀的來寫就是:

Date(int year,int month,int day)
{
    this->_year = year;
    this->_month = month;
    this->_day = day;
}

而我們平時會省略this ,當時實際上他是存在的。
又例如,在呼叫賦值運算子時

A operator=(const A& B)
{
    _a =  B._a;
    return *this;
}
A a(1);
A b(2);
a = b;

a = b 實際上就是
a.operator(&a,b);
A operator=(const A& B)
{
this->_a = B._a;
return *this;
}