C++ 類 & 對象

来源:http://www.cnblogs.com/ivan0512/archive/2017/10/14/7666899.html
-Advertisement-
Play Games

C++類和對象的基本簡介,包括構造函數、析構函數、拷貝構造函數、友元函數、內聯函數、類的this指針、靜態成員等內容概念介紹。 ...


說明:本文章內容大多來源於網路http://www.runoob.com/cplusplus/cpp-classes-objects.html,在此整理記錄自己的學習過程。

一、 簡介

1.類用於指定對象的形式,它包含了數據表示法和用於處理數據的方法。類中的數據和方法稱為類的成員。函數在一個類中被稱為類的成員。

2.類提供了對象的藍圖,所以基本上,對象是根據類來創建的。聲明類的對象,就像聲明基本類型的變數一樣。

二、類成員函數

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

2.成員函數可以定義在類定義內部,或者單獨使用範圍解析運算符 :: 來定義。在類定義中定義的成員函數把函數聲明為內聯的,即便沒有使用 inline 標識符。

 1 class Box
 2 {
 3    public:
 4       double length;      // 長度
 5       double breadth;     // 寬度
 6       double height;      // 高度
 7    
 8       double getVolume(void)
 9       {
10          return length * breadth * height;
11       }
12 };

或者

1 double Box::getVolume(void)
2 {
3     return length * breadth * height;
4 }

三、構造函數

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

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

四、析構函數

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

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

註:刪除類對象時會調用析構函數;程式跳出對象作用域時會調用析構函數。

五、拷貝構造函數

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

  • 通過使用另一個同類型的對象來初始化新創建的對象。

    1 Box box2=box1;

     

  • 複製對象把它作為參數傳遞給函數。

    1 printwidth(box1);

     

  • 複製對象,並從函數返回這個對象。

如果在類中沒有定義拷貝構造函數,編譯器會自行定義一個。如果類帶有指針變數,並有動態記憶體分配,則它必須有一個拷貝構造函數。拷貝構造函數的最常見形式如下:

1 classname (const classname &obj) {//obj 是一個對象引用,該對象是用於初始化另一個對象的。
2    // 構造函數的主體
3 }

六、友元函數

類的友元函數是定義在類外部,但有權訪問類的所有私有(private)成員和保護(protected)成員。儘管友元函數的原型有在類的定義中出現過,但是友元函數並不是成員函數。

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

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

1 class Box
2 {
3    double width;
4 public:
5    double length;
6    friend void printWidth( Box box );
7    void setWidth( double wid );
8 };

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

1 friend class ClassTwo;

七、內聯函數

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

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

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

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

Tip:

只有當函數只有 10 行甚至更少時才將其定義為內聯函數.

定義: 當函數被聲明為內聯函數之後, 編譯器會將其內聯展開, 而不是按通常的函數調用機制進行調用.

優點: 當函數體比較小的時候, 內聯該函數可以令目標代碼更加高效. 對於存取函數以及其它函數體比較短, 性能關鍵的函數, 鼓勵使用內聯.

缺點: 濫用內聯將導致程式變慢. 內聯可能使目標代碼量或增或減, 這取決於內聯函數的大小. 內聯非常短小的存取函數通常會減少代碼大小, 但內聯一個相當大的函數將戲劇性的增加代碼大小. 現代處理器由於更好的利用了指令緩存, 小巧的代碼往往執行更快。

結論: 一個較為合理的經驗準則是, 不要內聯超過 10 行的函數. 謹慎對待析構函數, 析構函數往往比其錶面看起來要更長, 因為有隱含的成員和基類析構函數被調用!

另一個實用的經驗準則: 內聯那些包含迴圈或 switch 語句的函數常常是得不償失 (除非在大多數情況下, 這些迴圈或 switch 語句從不被執行).

有些函數即使聲明為內聯的也不一定會被編譯器內聯, 這點很重要; 比如虛函數和遞歸函數就不會被正常內聯. 通常, 遞歸函數不應該聲明成內聯函數.(遞歸調用堆棧的展開並不像迴圈那麼簡單, 比如遞歸層數在編譯時可能是未知的, 大多數編譯器都不支持內聯遞歸函數). 虛函數內聯的主要原因則是想把它的函數體放在類定義內, 為了圖個方便, 抑或是當作文檔描述其行為, 比如精短的存取函數.

 八、this指針

在 C++ 中,每一個對象都能通過 this 指針來訪問自己的地址。this 指針是所有成員函數的隱含參數。因此,在成員函數內部,它可以用來指向調用對象。

友元函數沒有 this 指針,因為友元不是類的成員。只有成員函數才有 this 指針。

下麵的實例有助於更好地理解 this 指針的概念:

 1 #include <iostream>
 2  
 3 using namespace std;
 4 
 5 class Box
 6 {
 7    public:
 8       // 構造函數定義
 9       Box(double l=2.0, double b=2.0, double h=2.0)
10       {
11          cout <<"Constructor called." << endl;
12          length = l;
13          breadth = b;
14          height = h;
15       }
16       double Volume()
17       {
18          return length * breadth * height;
19       }
20       int compare(Box box)
21       {
22          return this->Volume() > box.Volume();
23       }
24    private:
25       double length;     // Length of a box
26       double breadth;    // Breadth of a box
27       double height;     // Height of a box
28 };
29 
30 int main(void)
31 {
32    Box Box1(3.3, 1.2, 1.5);    // Declare box1
33    Box Box2(8.5, 6.0, 2.0);    // Declare box2
34 
35    if(Box1.compare(Box2))
36    {
37       cout << "Box2 is smaller than Box1" <<endl;
38    }
39    else
40    {
41       cout << "Box2 is equal to or larger than Box1" <<endl;
42    }
43    return 0;
44 }

 

編譯執行結果

1 Constructor called.
2 Constructor called.
3 Box2 is equal to or larger than Box1

 

九、指向類的指針

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

十、類的靜態成員

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

2.靜態成員在類的所有對象中是共用的。如果不存在其他的初始化語句,在創建第一個對象時,所有的靜態數據都會被初始化為零。

3.不能把靜態成員的初始化放置在類的定義中,但是可以在類的外部通過使用範圍解析運算符 :: 來重新聲明靜態變數從而對它進行初始化

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

靜態成員函數只能訪問靜態成員數據其他靜態成員函數類外部的其他函數

靜態成員函數有一個類範圍,他們不能訪問類的 this 指針。您可以使用靜態成員函數來判斷類的某些對象是否已被創建。

靜態成員函數與普通成員函數的區別:

  • 靜態成員函數沒有 this 指針,只能訪問靜態成員(包括靜態成員變數和靜態成員函數)。
  • 普通成員函數有 this 指針,可以訪問類中的任意成員;而靜態成員函數沒有 this 指針。
 1 #include <iostream>
 2  
 3 using namespace std;
 4 
 5 class Box
 6 {
 7    public:
 8       static int objectCount;
 9       // 構造函數定義
10       Box(double l=2.0, double b=2.0, double h=2.0)
11       {
12          cout <<"Constructor called." << endl;
13          length = l;
14          breadth = b;
15          height = h;
16          // 每次創建對象時增加 1
17          objectCount++;
18       }
19       double Volume()
20       {
21          return length * breadth * height;
22       }
23       static int getCount()
24       {
25          return objectCount;
26       }
27    private:
28       double length;     // 長度
29       double breadth;    // 寬度
30       double height;     // 高度
31 };
32 
33 // 初始化類 Box 的靜態成員
34 int Box::objectCount = 0;
35 
36 int main(void)
37 {
38   
39    // 在創建對象之前輸出對象的總數
40    cout << "Inital Stage Count: " << Box::getCount() << endl;
41 
42    Box Box1(3.3, 1.2, 1.5);    // 聲明 box1
43    Box Box2(8.5, 6.0, 2.0);    // 聲明 box2
44 
45    // 在創建對象之後輸出對象的總數
46    cout << "Final Stage Count: " << Box::getCount() << endl;
47 
48    return 0;
49 }

 

編譯執行結果

1 Inital Stage Count: 0
2 Constructor called.
3 Constructor called.
4 Final Stage Count: 2

 

十一、綜合測試實驗

執行測試代碼,及其輸出結果如下所示:

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 class Box{
 6     double width;//預設訪問修飾符為private
 7     double *high;//【當類成員變數是指針時,需在構造函數和拷貝構造函數中為其申請記憶體,併在析構函數中刪除記憶體】
 8 public:
 9     void setWidth(double wid);
10     void setHigh(double hig);
11     double getHigh( void );
12     Box(double wid, double hig);//構造函數
13     ~Box(void);//析構函數
14     Box(const Box &obj);//拷貝構造函數
15 
16     friend void printwidth(Box box);//友元函數
17 };
18 void Box::setWidth(double wid)
19 {
20     width = wid;
21 }
22 void Box::setHigh(double hig)
23 {
24     *high = hig;
25 }
26 double Box::getHigh( void )
27 {
28     return *high;
29 }
30 Box::Box(double wid, double hig)
31 {
32     cout << "調用構造函數" << endl;
33     width = wid;
34     high = new double;//申請記憶體
35     *high = hig;
36 }
37 Box::~Box(void)
38 {
39     cout << "調用析構函數並釋放記憶體" << endl;
40     delete high;//釋放記憶體
41 }
42 Box::Box(const Box &obj)
43 {
44     cout << "調用拷貝構造函數" << endl;
45     width = obj.width;
46     high = new double;//申請記憶體
47     *high = *obj.high;
48 }
49 //友元函數不是類成員變數,但需在類中聲明
50 void printwidth(Box box)
51 {
52     cout << "調用友元函數" << endl;
53     cout << "width of box :" << box.width << endl;
54 }
55 void printhigh(Box obj)
56 {
57     cout << "high  of box :" << obj.getHigh() << endl;
58 }
59 //程式主函數
60 int main( )
61 {
62     Box box1(12,15);
63     Box box2=box1;
64 
65     //輸出width、high
66     printwidth(box1);
67     printhigh(box1);
68     printwidth(box2);
69     printhigh(box2);
70 
71     //設置width、high
72     box2.setWidth(13);
73     box2.setHigh(16);
74 
75     //輸出width、high
76     printwidth(box1);
77     printhigh(box1);
78     printwidth(box2);
79     printhigh(box2);
80 
81     return 0;//調用析構函數(釋放box1、box2)
82 }

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 對於一個初學者來說for迴圈可能會擊潰很多人,因為網上找的python的for迴圈沒有詳細的介紹for迴圈的條件以及for迴圈後面定義的東西是什麼意思。首先我先舉一個常用的例子。 for i in range(1,10) : print i 上面這兩條代碼是用來在屏幕上列印1到9的。這裡就不對ran ...
  • 在上一章中,我們已經搭建好了struts2的一個開發環境,那麼這一章就來做一個簡單的登錄功能,以及介紹和使用struts2裡面一個重要的東西-通配符。 第一步,在WebContent下麵新建一個login.jsp的頁面,裡面使用form表單實現一個簡單的登錄頁面。 第二步:打開上一章中建好的Logi ...
  • 配置環境 1. 導入jar包,Struts2官網:http://struts.apache.org/ 2. 創建Action類 繼承ActionSupport (ActionSupport類是一個工具類,它已經實現了Action介面。除此之外,它還實現了Validateable介面,提供了數據校驗功 ...
  • 幾周前,我開始工作於一個證券投資組合網站。雖然我只能使用 React 完成整個網站,但我決定使用 Go 來創建一個可以處理某些任務(例如發送 email)的 API 伺服器,相信這是一個很好的做法。我其中的一個頁面是一個 contact 頁面,目前看起來像這樣:我想使用專門為此 contact 表單... ...
  • #include <iostream>#include<cstdio>using namespace std;int main(){ freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); int a,b; while(ci ...
  • 剛看spring3實戰書籍第一章 切麵以前沒有關註過 現在看到了 隨手試驗一下 AOP AOP(Aspect Oriented Programming),即面向切麵編程,可以說是OOP(Object Oriented Programming,面向對象編程)的補充和完善。OOP引入封裝、繼承、多態等概 ...
  • 多線程的目的 為什麼要使用多線程?可以簡單的分兩個方面來說: 在多個cpu核心下,多線程的好處是顯而易見的,不然多個cpu核心只跑一個線程其他的核心就都浪費了; 即便不考慮多核心,在單核下,多線程也是有意義的,因為在一些操作,比如IO操作阻塞的時候,是不需要cpu參與的,這時候cpu就可以另開一個線 ...
  • 說到原子,類似於以下的代碼可能人人都可以看出貓膩。 我想大多數人都知道其結果未必會得到1000000000。 測試一下吧。 可是真的知道貓膩了嗎?如果我編譯的時候優化一下呢? 運行速度一下子變的飛快,而且似乎都得到了10億。 這裡,mythread里cnt自加5億次被優化成了 cnt += 5000 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...