C++中類與對象的講解(通俗易懂)

1.類成員函數類的成員函數是指那些把定義和原型寫在類定義內部的函數,就像類定義中的其他變量一樣。

2.類訪問修飾符類成員可以被定義為 public、private 或 protected。默認情況下是定義為 private。

3.構造函數 & 析構函數類的構造函數是一種特殊的函數,在創建一個新的對象時調用。類的析構函數也是一種特殊的函數,在刪除所創建的對象時調用。

4.C++ 拷貝構造函數拷貝構造函數,是一種特殊的構造函數,它在創建對象時,是使用同一類中之前創建的對象來初始化新創建的對象。

5.C++ 友元函數友元函數可以訪問類的 private 和 protected 成員。

6.C++ 內聯函數通過內聯函數,編譯器試圖在調用函數的地方擴展函數體中的代碼。

7.C++ 中的 this 指針每個對象都有一個特殊的指針 this,它指向對象本身。

8.C++ 中指向類的指針指向類的指針方式如同指向結構的指針。實際上,類可以看成是一個帶有函數的結構。

9.C++ 類的靜態成員類的數據成員和函數成員都可以被聲明為靜態的。

C++中類與對象的講解(通俗易懂)

接下來我們一一仔細講解:

的成員函數是指那些把定義和原型寫在類定義內部的函數,就像類定義中的其他變量一樣。類成員函數是類的一個成員,它可以操作類的任意對象,可以訪問對象中的所有成員。

class Box

{

public:

double length; // 長度

double breadth; // 寬度

double height; // 高度

double getVolume(void);// 返回體積

};

Box

{

public:

double length; // 長度

double breadth; // 寬度

double height; // 高度

double getVolume(void);// 返回體積

};

成員函數可以定義在類定義內部,或者單獨使用範圍解析運算符 :: 來定義。在類定義中定義的成員函數把函數聲明為內聯的,即便沒有使用 inline 標識符。所以您可以按照如下方式定義 Volume() 函數:

class Box

{

public:

double length; // 長度

double breadth; // 寬度

double height; // 高度

double getVolume(void)

{

return length * breadth * height;

}

};

Box

{

public:

double length; // 長度

double breadth; // 寬度

double height; // 高度

double getVolume(void)

{

return length * breadth * height;

}

};

C++中類與對象的講解(通俗易懂)

您也可以在類的外部使用範圍解析運算符 :: 定義該函數,如下所示:

double Box::getVolume(void)

{

return length * breadth * height;

}

Box::getVolume(void)

{

return length * breadth * height;

}

在這裡,需要強調一點,在 :: 運算符之前必須使用類名。調用成員函數是在對象上使用點運算符(.),這樣它就能操作與該對象相關的數據,如下所示:

Box myBox; // 創建一個對象

myBox.getVolume(); // 調用該對象的成員函數

myBox; // 創建一個對象

myBox.getVolume(); // 調用該對象的成員函數

一個類可以有多個 public、protected 或 private 標記區域。每個標記區域在下一個標記區域開始之前或者在遇到類主體結束右括號之前都是有效的。成員和類的默認訪問修飾符是 private。

class Base {

public:

// public members go here

protected:

// protected members go here

private:

// private members go here

};

Base {

public:

// public members go here

protected:

// protected members go here

private:

// private members go here

};

公有成員在程序中類的外部是可訪問的。您可以不使用任何成員函數來設置和獲取公有變量的值。就是說你可以直接用對象+“.”(點運算符)的方式來為公有變量賦值。

私有成員變量或函數在類的外部是不可訪問的,甚至是不可查看的。只有類和友元函數可以訪問私有成員。(這個和Java不一樣,Java類中默認是public)

默認情況下,類的所有成員都是私有的。

實際操作中,我們一般會在私有區域定義數據,在公有區域定義相關的函數,以便在類的外部也可以調用這些函數。這個方式確實好,有點裡應外合的感覺。

保護成員變量或函數與私有成員十分相似,但有一點不同,保護成員在派生類(即子類)中是可訪問的。

下面的實例與前面的實例類似,在這裡 width 成員可被派生類 smallBox 的任何成員函數訪問。(“:”操作符相當於繼承)

#include

using namespace std;

class Box

{

protected:

double width;

};

class SmallBox:Box // SmallBox 是派生類

{

public:

void setSmallWidth( double wid );

double getSmallWidth( void );

};

// 子類的成員函數

double SmallBox::getSmallWidth(void)

{

return width ;

}

void SmallBox::setSmallWidth( double wid )

{

width = wid;

}

// 程序的主函數

int main( )

{

SmallBox box;

// 使用成員函數設置寬度

box.setSmallWidth(5.0);

cout << "Width of box : "<< box.getSmallWidth() << endl;

return 0;

}

using namespace std;

class Box

{

protected:

double width;

};

class SmallBox:Box // SmallBox 是派生類

{

public:

void setSmallWidth( double wid );

double getSmallWidth( void );

};

// 子類的成員函數

double SmallBox::getSmallWidth(void)

{

return width ;

}

void SmallBox::setSmallWidth( double wid )

{

width = wid;

}

// 程序的主函數

int main( )

{

SmallBox box;

// 使用成員函數設置寬度

box.setSmallWidth(5.0);

cout << "Width of box : "<< box.getSmallWidth() << endl;

return 0;

}

類的構造函數是類的一種特殊的成員函數,它會在每次創建類的新對象時執行。

構造函數的名稱與類的名稱是完全相同的,並且不會返回任何類型,也不會返回 void。構造函數可用於為某些成員變量設置初始值。

默認的構造函數沒有任何參數,但如果需要,構造函數也可以帶有參數。這樣在創建對象時就會給對象賦初始值。

C++中類與對象的講解(通俗易懂)

使用初始化列表來初始化字段:

Line::Line( double len): length(len)

{

cout << "Object is being created, length = " << len << endl;

}

::Line( double len): length(len)

{

cout << "Object is being created, length = " << len << endl;

}

上面的語法等同於如下語法:

Line::Line( double len)

{

cout << "Object is being created, length = " << len << endl;

length = len;

}

::Line( double len)

{

cout << "Object is being created, length = " << len << endl;

length = len;

}

假設有一個類 C,具有多個字段 X、Y、Z 等需要進行初始化,同理地,您可以使用上面的語法,只需要在不同的字段使用逗號進行分隔,如下所示:

C::C( double a, double b, double c): X(a), Y(b), Z(c)

{

....

}

::C( double a, double b, double c): X(a), Y(b), Z(c)

{

....

}

類的析構函數是類的一種特殊的成員函數,它會在每次刪除所創建的對象時執行。

析構函數的名稱與類的名稱是完全相同的,只是在前面加了個波浪號(~)作為前綴,它不會返回任何值,也不能帶有任何參數。析構函數有助於在跳出程序(比如關閉文件、釋放內存等)前釋放資源。

下面的實例有助於更好地理解析構函數的概念:

#include

using namespace std;

class Line

{

public:

void setLength( double len );

double getLength( void );

Line(); // 這是構造函數聲明

~Line(); // 這是析構函數聲明

private:

double length;

};

// 成員函數定義,包括構造函數

Line::Line(void)

{

cout << "Object is being created" << endl;

}

Line::~Line(void)

{

cout << "Object is being deleted" << endl;

}

void Line::setLength( double len )

{

length = len;

}

double Line::getLength( void )

{

return length;

}

// 程序的主函數

int main( )

{

Line line;

// 設置長度

line.setLength(6.0);

cout << "Length of line : " << line.getLength() <

return 0;

}

using namespace std;

class Line

{

public:

void setLength( double len );

double getLength( void );

Line(); // 這是構造函數聲明

~Line(); // 這是析構函數聲明

private:

double length;

};

// 成員函數定義,包括構造函數

Line::Line(void)

{

cout << "Object is being created" << endl;

}

Line::~Line(void)

{

cout << "Object is being deleted" << endl;

}

void Line::setLength( double len )

{

length = len;

}

double Line::getLength( void )

{

return length;

}

// 程序的主函數

int main( )

{

Line line;

// 設置長度

line.setLength(6.0);

cout << "Length of line : " << line.getLength() <

return 0;

}

當上面的代碼被編譯和執行時,它會產生下列結果:

Object is being created

Length of line : 6

Object is being deleted

is being created

Length of line : 6

Object is being deleted

可見構造函數與析構函數表面上是一個“~”的差別,其實作用恰恰相反,一個生成,一個回收。

拷貝構造函數是一種特殊的構造函數,它在創建對象時,是使用同一類中之前創建的對象來初始化新創建的對象。拷貝構造函數通常用於:

3.拷貝構造函數調用的三種形式

3.1.一個對象作為函數參數,以值傳遞的方式傳入函數體;

3.2.一個對象作為函數返回值,以值傳遞的方式從函數返回;

3.3.一個對象用於給另外一個對象進行初始化(常稱為複製初始化)。

總結:當某對象是按值傳遞時(無論是作為函數參數,還是作為函數返回值),編譯器都會先建立一個此對象的臨時拷貝,而在建立該臨時拷貝時就會調用類的拷貝構造函數。

如果在類中沒有定義拷貝構造函數,編譯器會自行定義一個。如果類帶有指針變量,並有動態內存分配,則它必須有一個拷貝構造函數。該構造函數完成對象之間的位拷貝。(位拷貝又稱淺拷貝,後面將進行說明。)自定義拷貝構造函數是一種良好的編程風格,它可以阻止編譯器形成默認的拷貝構造函數,提高源碼效率。拷貝構造函數的最常見形式如下:

classname (const classname &obj) {

// 構造函數的主體

}

(const classname &obj) {

// 構造函數的主體

}

在這裡,obj 是一個對象引用,該對象是用於初始化另一個對象的。

在某些狀況下,類內成員變量需要動態開闢堆內存,如果實行位拷貝,也就是把對象裡的值完全複製給另一個對象,如A=B。這時,如果B中有一個成員變量指針已經申請了內存,那A中的那個成員變量也指向同一塊內存。這就出現了問題:當B把內存釋放了(如:析構),這時A內的指針就是野指針了,出現運行錯誤。事實上這就要用到深拷貝了,要自定義拷貝構造函數。(這一段其實很好理解)

深拷貝和淺拷貝可以簡單理解為:如果一個類擁有資源,當這個類的對象發生複製過程的時候,資源重新分配,這個過程就是深拷貝,反之,沒有重新分配資源,就是淺拷貝

淺拷貝資源後在釋放資源的時候會產生資源歸屬不清的情況導致程序運行出錯。一定要注意類中是否存在指針成員。

友元函數並不是成員函數。友元可以是一個函數,該函數被稱為友元函數;友元也可以是一個類,該類被稱為友元類,在這種情況下,整個類及其所有成員都是友元。

如果要聲明函數為一個類的友元,需要在類定義中該函數原型前使用關鍵字 friend,如下所示:

class Box

{

double width;

public:

double length;

friend void printWidth( Box box );

void setWidth( double wid );

};

Box

{

double width;

public:

double length;

friend void printWidth( Box box );

void setWidth( double wid );

};

聲明類 ClassTwo 的所有成員函數作為類 ClassOne 的友元,需要在類 ClassOne 的定義中放置如下聲明:

friend class ClassTwo;

class ClassTwo;

C++ 內聯函數是通常與類一起使用。如果一個函數是內聯的,那麼在編譯時,編譯器會把該函數的代碼副本放置在每個調用該函數的地方。

對內聯函數進行任何修改,都需要重新編譯函數的所有客戶端,因為編譯器需要重新更換一次所有的代碼,否則將會繼續使用舊的函數。

如果想把一個函數定義為內聯函數,則需要在函數名前面放置關鍵字 inline,在調用函數之前需要對函數進行定義。如果已定義的函數多於一行,編譯器會忽略 inline 限定符。

在類定義中的定義的函數都是內聯函數,即使沒有使用 inline 說明符。

一個指向 C++ 類的指針與指向結構的指針類似,訪問指向類的指針的成員,需要使用成員訪問運算符 ->,就像訪問指向結構的指針一樣。與所有的指針一樣,您必須在使用指針之前,對指針進行初始化。

C++中類與對象的講解(通俗易懂)

我們可以使用 static 關鍵字來把類成員定義為靜態的。當我們聲明類的成員為靜態時,這意味著無論創建多少個類的對象,靜態成員都只有一個副本。

靜態成員在類的所有對象中是共享的。如果不存在其他的初始化語句,在創建第一個對象時,所有的靜態數據都會被初始化為零。我們不能把靜態成員放置在類的定義中,但是可以在類的外部通過使用範圍解析運算符 :: 來重新聲明靜態變量從而對它進行初始化,如下面的實例所示。

下面的實例有助於更好地理解靜態數據成員的概念:

#include

using namespace std;

class Box

{

public:

static int objectCount;

// 構造函數定義

Box(double l=2.0, double b=2.0, double h=2.0)

{

cout <

length = l;

breadth = b;

height = h;

// 每次創建對象時增加 1

objectCount++;

}

double Volume()

{

return length * breadth * height;

}

private:

double length; // 長度

double breadth; // 寬度

double height; // 高度

};

// 初始化類 Box 的靜態成員

int Box::objectCount = 0;

int main(void)

{

Box Box1(3.3, 1.2, 1.5); // 聲明 box1

Box Box2(8.5, 6.0, 2.0); // 聲明 box2

// 輸出對象的總數

cout << "Total objects: " << Box::objectCount << endl;

return 0;

}

using namespace std;

class Box

{

public:

static int objectCount;

// 構造函數定義

Box(double l=2.0, double b=2.0, double h=2.0)

{

cout <

length = l;

breadth = b;

height = h;

// 每次創建對象時增加 1

objectCount++;

}

double Volume()

{

return length * breadth * height;

}

private:

double length; // 長度

double breadth; // 寬度

double height; // 高度

};

// 初始化類 Box 的靜態成員

int Box::objectCount = 0;

int main(void)

{

Box Box1(3.3, 1.2, 1.5); // 聲明 box1

Box Box2(8.5, 6.0, 2.0); // 聲明 box2

// 輸出對象的總數

cout << "Total objects: " << Box::objectCount << endl;

return 0;

}

當上面的代碼被編譯和執行時,它會產生下列結果:

Constructor called.

Constructor called.

Total objects: 2

called.

Constructor called.

Total objects: 2

如果把函數成員聲明為靜態的,就可以把函數與類的任何特定對象獨立開來。靜態成員函數即使在類對象不存在的情況下也能被調用,靜態函數只要使用類名加範圍解析運算符 :: 就可以訪問。

靜態成員函數只能訪問靜態數據成員,不能訪問其他非靜態成員。

寫在最後

喜歡此篇文章或覺得這篇文章對你有幫助的讀者可以點播關注或者轉發,私信小編001即可獲得小編自己整理的一份2018最新的C/C++資料和0基礎入門教程,歡迎初學和進階中的小夥伴


分享到:


相關文章: