C++——類的入門

先借這個位置掛一下某大佬的博客:除了系圍巾什麼都會的dalao

在C++中,有一個叫做類的東西……鑑於我上課的時候大部分時間都在划水,所以只隱隱約約聽到什麼函數的封裝啊,什麼繼承與派生之類的,完全不瞭解,眼看着就要期末了,不得不開始自救計劃……


§類的格式

首先,還是一個老生常談的問題:類,是什麼,幹什麼的,怎麼實現的?

什麼是類呢?

簡言之,在C++中,如果看到class關鍵字,那這個就是類的標誌。

首先,我們選取被人吐槽嘲諷的譚書上的一道例題作爲第一個栗子(其實譚書還是不錯的,只是有少數錯誤,大家要理解畢竟這麼厚的書,一點都不錯還是很困難的)

選自第三版249頁例題9.2:求體積

代碼如下:

#include<bits/stdc++.h>
using namespace std;
class Box
{
public:
    Box(int,int,int);
    int volume();
private:
    int height;
    int width;
    int length;
};
Box::Box(int h,int w,int len)
{
    height=h;
    width=w;
    length=len;
}
int Box::volume()
{
    return(height*width*length);
}
int main()
{
    Box box1(12,25,30);
    cout<<"The volume of box1 is "<<box1.volume()<<endl;
    Box box2(15,30,21);
    cout<<"The volume of box2 is "<<box2.volume()<<endl;
    return 0;
}

輸出:

The volume of box1 is 9000
The volume of box2 is 9450

嗯,先講一個花絮吧……

所以在此也提醒大家,一定要注意標點,無論是在寫語文作文、英語作文還是代碼的時候都要注意標點(這裏突然想到我的英語老師曾經多次批評我亂用標點,比如在舉例子的時候逗號經常用錯)。

首先,還是針對這段代碼本身談一談一些個人看法。

先看看第一段,有位大佬跟我介紹——類和結構體差距不大。所以我們可以很容易在類中看到結構體的影子。比如:

Box::Box(int h,int w,int len)

這裏,Box就在開頭的位置頂替了Int之類的變量類型。
讓我先安利一個博客:C++類(Class)總結

大家都有看到兩個關鍵字:public和private,具體的作用,如這兩個英語單詞本身的意思所示:

class 類名
    {
        public:
            //公共的行爲或屬性

        private:
            //公共的行爲或屬性
    };


 ※注意:publicprivate 爲屬性/方法限制的關鍵字, private 表示該部分內容是私密的, 不能被外部所訪問或調用, 只能被本類內部訪問; 而 public 表示公開的屬性和方法, 外界可以直接訪問或者調用。
            一般來說類的屬性成員都應設置爲private, public只留給那些被外界用來調用的函數接口, 但這並非是強制規定, 可以根據需要進行調整;

還有---->不要忘了☞☞☞最後有一個分號//就像結構體一樣


接下來,就是百度百科內容:
在現實世界中,經常有屬於同一類的對象。例如,你的自行車只是世界上很多自行車中的一輛。在面向對象軟件中,也有很多共享相同特徵的不同的對象:矩形、僱用記錄、視頻剪輯等。可以利用這些對象的相同特徵爲它們建立一個集合。而這個集合就稱爲類是定義同一類所有對象的變量和方法的藍圖或原型。例如,可以建立一個定義包含當前檔位等實例變量的自行車類。這個類也定義和提供了實例方法(變檔、剎車)的實現。實例變量的值由類的每個實例提供。因此,當你創建自行車類以後,必須在使用之前對它進行實例化。當創建類的實例時,就建立了這種類型的一個對象,然後系統爲類定義的實例變量分配內存。然後可以調用對象的實例方法實現一些功能。相同類的實例共享相同的實例方法。
除了實例變量和方法,類也可以定義類變量和類方法。可以從類的實例中或者直接從類中訪問類變量和方法。類方法只能操作類變量 - 不必訪問實例變量或實例方法。系統在第一次在程序中遇到一個類時爲這個類建立它的所有類變量的拷貝 - 這個類的所有實例共享它的類變量。
→→對象提供了模型化和信息隱藏的好處。類提供了可重用性的好處。

可以發現,這裏對於函數的定義多了兩個冒號!


-------------------------------------這裏是分割線---------------------------------------------
上面廢話了這麼多,終於要進入正題了:

格式:請大家原諒懶惰的我……就觀看上面安利的博客吧

然後上面那段代碼,在菜鳥教程上還有別的寫法:
#include <iostream>
 
using namespace std;
 
class Box
{
   public:
      double length;   // 長度
      double breadth;  // 寬度
      double height;   // 高度
};
 
int main( )
{
   Box Box1;        // 聲明 Box1,類型爲 Box
   Box Box2;        // 聲明 Box2,類型爲 Box
   double volume = 0.0;     // 用於存儲體積
 
   // box 1 詳述
   Box1.height = 5.0; 
   Box1.length = 6.0; 
   Box1.breadth = 7.0;
 
   // box 2 詳述
   Box2.height = 10.0;
   Box2.length = 12.0;
   Box2.breadth = 13.0;
 
   // box 1 的體積
   volume = Box1.height * Box1.length * Box1.breadth;
   cout << "Box1 的體積:" << volume <<endl;
 
   // box 2 的體積
   volume = Box2.height * Box2.length * Box2.breadth;
   cout << "Box2 的體積:" << volume <<endl;
   return 0;
}


§類的繼承和派生

還是先安利一個c++類的繼承和派生

老師上課舉例子說到了基因突變(我覺得還是應該感謝老師沒有說出染色體變異和基因重組,要不然我會感覺到回到可怕的高三)

其實……

這個跟繼承差不多吧,比如我的父母生了我,然後我從父母那裏得到的性狀就是繼承。

然後我們可以把繼承理解爲一個動詞,其結果是一個名詞,也就是派生。


一、基本概念

1、類的繼承,是新的類從已有類那裏得到已有的特性。或從已有類產生新類的過程就是類的派生。原有的類稱爲基類或父類,產生的新類稱爲派生類或子類。

 

2、派生類的聲明:

class 派生類名:繼承方式 基類名1, 繼承方式 基類名2,...,繼承方式 基類名n

{

    派生類成員聲明;

};

 

3、一個派生類可以同時有多個基類,這種情況稱爲多重繼承,派生類只有一個基類,稱爲單繼承。直接派生,間接派生。

 

4、繼承方式規定了如何訪問基類繼承的成員。繼承方式有public, private, protected。如果不顯示給出繼承方式,默認爲private繼承。繼承方式指定了派生類成員以及類外對象對於從基類繼承來的成員的訪問權限。

 

5、派生類繼承基類中除構造和析構函數以外的所有成員。

 

6、派生類生成:

   吸收基類成員(除構造析構函數以外的所有成員);

   改造基類成員(根據繼承方式調整基類成員的訪問,函數在子類中的覆蓋,以及虛函數在子類中的覆蓋);

   添加新的成員;

 

7、公有繼承

當類的繼承方式爲公有繼承時,基類的公有和保護成員的訪問屬性在派生類中不變,而基類的私有成員不可訪問。即基類的公有成員和保護成員被繼承到派生類中仍作爲派生類的公有成員和保護成員。派生類的其他成員可以直接訪問它們。無論派生類的成員還是派生類的對象都無法訪問基類的私有成員。

 

8、私有繼承

當類的繼承方式爲私有繼承時,基類中的公有成員和保護成員都以私有成員身份出現在派生類中,而基類的私有成員在派生類中不可訪問。基類的公有成員和保護成員被繼承後作爲派生類的私有成員,派生類的其他成員可以直接訪問它們,但是在類外部通過派生類的對象無法訪問。無論是派生類的成員還是通過派生類的對象,都無法訪問從基類繼承的私有成員。通過多次私有繼承後,對於基類的成員都會成爲不可訪問。因此私有繼承比較少用。

 

9、保護繼承

保護繼承中,基類的公有成員和私有成員都以保護成員的身份出現在派生類中,而基類的私有成員不可訪問。派生類的其他成員可以直接訪問從基類繼承來的公有和保護成員,但是類外部通過派生類的對象無法訪問它們,無論派生類的成員還是派生類的對象,都無法訪問基類的私有成員。


二、派生類的構造函數和析構函數
1、派生類中由基類繼承而來的成員的初始化工作還是由基類的構造函數完成,然後派生類中新增的成員在派生類的構造函數中初始化。
 
2、派生類構造函數的語法:
派生類名::派生類名(參數總表):基類名1(參數表1),基類名(參數名2)....基類名n(參數名n),內嵌子對象1(參數表1),內嵌子對象2(參數表2)....內嵌子對象n(參數表n)
{
    派生類新增成員的初始化語句;
}
注:構造函數的初始化順序並不以上面的順序進行,而是根據聲明的順序初始化。
 
3、如果基類中沒有不帶參數的構造函數,那麼在派生類的構造函數中必須調用基類構造函數,以初始化基類成員。
 
4、派生類構造函數執行的次序:
   調用基類構造函數,調用順序按照它們被繼承時聲明的順序(從左到右);
   調用內嵌成員對象的構造函數,調用順序按照它們在類中聲明的順序;
   派生類的構造函數體中的內容。

剩下的內容,大家去原博客看吧(✺ω✺)


嗯,大致就先到這裏啦,之後想到還會接着寫的(*╹▽╹*)


(✺ω✺),突然又想再寫一點了

之前在很多有關C++類的學習中,會看到這段代碼:

#include <iostream>
using namespace std;
class Point
{
public:
    void setPoint(int x, int y) //實現setPoint函數
    {
        xPos = x;
        yPos = y;
    }

    void printPoint()       //實現printPoint函數
    {
        cout<< "x = " << xPos << endl;
        cout<< "y = " << yPos << endl;
    }

private:
    int xPos;
    int yPos;
};

int main()
{
    Point M;        //用定義好的類創建一個對象 點M
    M.setPoint(10, 20); //設置 M點 的x,y值
    M.printPoint();     //輸出 M點 的信息

    return 0;
}


這個註釋寫的挺詳細的,但是還想再補充一下:

如果,我們省掉private那一部分會怎麼樣?

#include<bits/stdc++.h>
using namespace std;
class Point
{
public:
    void setPoint(int x,int y);
    void printPoint()
    {
        cout<<"x = "<<x<<endl;
        cout<<"y = "<<y<<endl;
    }
};
int main()
{
    Point M;
    M.setPoint(10,20);
    M.printPoint();
    return 0;
}

既然提到了,說明肯定是報錯了
報錯信息如下:

Compilation Failed


/usercode/file.cpp: In member function ‘void Point::printPoint()’:
/usercode/file.cpp:9:23: error: ‘x’ was not declared in this scope
         cout<<"x = "<<x<<endl;
                       ^
/usercode/file.cpp:10:23: error: ‘y’ was not declared in this scope
         cout<<"y = "<<y<<endl;
                       ^

也就是說:即使兩個都在public下,x和y也不算是聲明,我懷疑原因如下↓

雖然都在public中,但是……可以發現,這種寫法:

void setPoint(int x,int y);

是不是很像自定義函數的申明,而自定義函數中括號中的參變量(不好意思,我也不知道叫啥)在函數外是不可以直接引用的,也就是如果之後需要,得重新定義參變量。所以,在這裏也一樣,如果這個函數只是申明,那麼函數中的參變量既不能使用別的函數也不能被別的函數調用。


那麼既然如此,如果按照自定義函數去理解,可以嗎?

#include<bits/stdc++.h>
using namespace std;
class Point
{
public:
    void setPoint(int x,int y);
    void printPoint()
    {
        cout<<"x = "<<xPos<<endl;
        cout<<"y = "<<yPos<<endl;
    }
    void setPoint(int x,int y)
    {
        xPos=x;
        yPos=y;
    }
private:
    int xPos;
    int yPos;
};
int main()
{
    Point M;
    M.setPoint(10,20);
    M.printPoint();
    return 0;
}

答案還是否定的……報錯信息如下:

Compilation Failed


/usercode/file.cpp:12:10: error: ‘void Point::setPoint(int, int)’ cannot be overloaded
     void setPoint(int x,int y)
          ^
/usercode/file.cpp:6:10: error: with ‘void Point::setPoint(int, int)’
     void setPoint(int x,int y);
          ^

即:函數不能被重載。

#include<bits/stdc++.h>
using namespace std;
class Point
{
public:
    void printPoint()
    {
        cout<<"x = "<<xPos<<endl;
        cout<<"y = "<<yPos<<endl;
    }
    void setPoint(int x,int y)
    {
        xPos=x;
        yPos=y;
    }
private:
    int xPos;
    int yPos;
};
int main()
{
    Point M;
    M.setPoint(10,20);
    M.printPoint();
    return 0;
}

調換順序無影響。
輸出:

x = 10
y = 20

若做如下調整:

void setPoint(int y,int x)
    {
        xPos=x;
        yPos=y;
    }


輸出:

x = 20
y = 10

就局部而言,還是與函數比較相像的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章