C++基礎學習第一天

類與對象

struct與class

聚合類

最初的C++稱為「帶類的C」,擴展了C語言的很多功能。在C++語言中,仍然可以使用C語言中的struct定義結構。

struct 結構名{
    類型 變數名;
    類型 變數名;
    ...
}

在C++中,聚合類是一種特殊類型的,用戶可以直接訪問其成員,並且具有特殊的初始化語法形式(可以提供一對花括弧括起來的成員初始值列表初始化聚合類的數據成員)。

聚合類應當滿足的條件:

  • 所有的成員都是public類型的(任何情況下,對象都可以通過成員運算符訪問成員);
  • 沒有定義任何構造函數;
  • 沒有類內初始值;
  • 沒有基類,也沒有虛函數。

舉個例子,定義一個聚合類Data

struct Data{
    int ival;
    string str;   
};

初始化可以這樣:

Data dval = {8,"Smith"};

注意:初始值的順序必須與成員聲明的順序一致。初始值列表中元素的個數如果少於類的成員數量,則靠後的成員被值初始化。初始值列表中元素的個數絕對不能少於類的成員數量。

C++對struct的擴展

C++中的struct不僅可以包含數據,還可以包含函數。

舉個例子:

#include<iostream>

using namespace std;
struct Complex{
    double real;
    double imag;
    void init(double r,double i){
        real = r;
        imag = i;
    }
    double getReal(){return real;}
    double getImag(){return imag;}
};

int main(){
    Complex c;
    c.init(2,3);
    cout <<c.getReal() <<"+" <<c.getImag() <<"i" <<endl;
    return 0;
}

小提示:在結構中數據成員後面帶分號,函數成員後面是不帶分號的,但是函數成員內需要帶分號,結構反括弧後面也是要加分號的,main結束是不加分號的。

說明:結構中的數據和函數稱為成員,realimag是數據成員。定義Complex結構後,就可以用它來定義變數,並能通過成員運算符訪問它的成員函數。

訪問許可權

為了實現資訊隱藏,限制對結構中某些成員的非法訪問,C++增高了3個訪問許可權限定符,用於設置結構中數據成員和函數成員的訪問許可權。

  • public

    被設置為public許可權的成員(包括數據成員和函數成員)稱為類的公有成員,可被任何函數訪問(包括結構內和結構外的函數)。

  • private

    被設置為private許可權的成員(包括數據成員和函數成員)稱為類的私有成員,僅供結構(類)的內部(自身成員函數)訪問。

  • protected

    protected與繼承有關。供結構(類)的內部及後代(派生類)訪問。

在C和C++中,如果沒有聲明訪問許可權,默認的訪問許可權是public。如果不想讓外部直接訪問需要加個private聲明為私有類型。C++結構的定義形式:

struct 類名{
    [public:]
    	成員;
    private:
    	成員;
    protected:
    	成員;
};

類(class)具有資訊隱藏的能力,能夠完成介面與實現的分離,用於把數據抽象的結果封裝成可以用於程式設計的抽象數據類型。是面向對象程式設計中通用的數據封裝工具。在C++中,class具有與struct完全相同的功能,用法一致。類是默認private

類也是一種自定義數據類型,用關鍵字class表示,用法與struct相同,形式如下:

class 類名{
    [private:]
    	成員;
    public:
    	成員;
    protected:
    	成員;
};

類名通常首字元大寫的標識符表示 ;一對花括弧界定了類的範圍;最後的分號必不可少,表示類聲明結束。

舉個例子:

class Complex
{
    private:
    	double real,imag;
    public:
    	void init(double r,double i){
            real = r;
            imag = i;
        }
    	double getReal(){return real;}
    	double getImag(){return imag;}
    	void print(){
        	cout <<c.getReal() <<"+" <<c.getImag() <<"i" <<endl;
    	}
};

對於類定義需要注意的問題:

  • 訪問說明符

    對於類聲明中的訪問說明符privatepublicprotected沒有先後主次之分,也沒有使用次數的限制。只是出於資訊隱藏的目的,將數據成員設置為private許可權,將需要讓外部函數訪問的成員設置為public許可權。

  • 類作用域

    classstruct後面的一對花括弧包圍的區域是一種獨立的作用域,稱為類域。類域內的數據和函數都稱為成員(數據稱為數據成員,函數常被稱為成員函數)。同一類域內的成員是不愛訪問許可權和先後次序的限制,相互間可以直接訪問。

  • 關鍵字struct和class

    C++的struct也是一種類,它與class具有相同的功能,用法也是完全相同。唯一區別是在沒有指定成員的訪問許可權時,默認的許可權是不一樣的。

抽象與封裝

類是對客觀世界中同類事物的抽象,它給出了屬於該類事物共有的屬性(數據成員)和操作(成員函數)。

類具有封裝特性。

  • 能夠把數據和演算法組合在一起,構成一個不可分割的整體;
  • 能夠有效地把類的內部數據隱藏起來,外部函數只能通過類的公有成員才能訪問類的內部數據。

抽象是對具體對象(問題)進行概括,抓住問題的本質,抽出這一類對象共有的性質,並加以描述的過程,抽象主要包括數據抽象和過程抽象。

抽象與封裝的區別:抽象是一種思維方式,而封裝是一種基於抽象性的操作方法。一般通過抽象,把所得到的數據資訊以封裝的技術將其重新整合,形成一個新的有機體,這就是類。

類的成員

數據成員

類的數據成員可以是任何數據類型,如整型、浮點型、字元型、數組、指針和引用等,也可以是另外一個類的對象或指向對象的指針,還可以是自身類的指針或引用,但不能是自身類的對象;可以是const常量,但不能是constexpr常量;可以用decltype推斷類型,但不能使用auto推斷類型;數據成員不能指定為extern的存儲類別。

C++支援在定義類的同時為類的數據成員賦初始值,舉個例子:

class X{
    private:
    	int a = 2;
    	int y = {3};
    	int b[3] = {1,2,3};
    	const int ci = a;
    public:
    	...
}

注意:類的定義或聲明只是在程式中增加的自定義數據類型,是沒有分配相應的記憶體空間。只有在實例化時,才會分配相應的空間,也才會在這時初始化數據成員。

成員函數

類的成員函數也稱為方法或服務。它可以在類內定義,也可以在類外定義;可以重載,也可以使用默認實參。

  • 成員函數的定義

    類的成員函數有兩種定義方式:

    • 聲明類時就給出成員函數的定義。

      class Complex
      {
          private:
          	double real,imag;
          public:
          	void init(double r,double i){
                  real = r;
                  imag = i;
              }
          	double getReal(){return real;}
          	double getImag(){return imag;}
      };
      
    • 在聲明類時,只聲明成員函數的原型,然後在外部定義成員函數。類外定義函數格式

      返回類型 類名::成員函數名(參數列表);
      

      其中,::是作用域運算符,用於說明這裡定義的函數是指定類中的一個成員函數。

      class Complex
      {
          private:
          	double real,imag;
          public:
          	void init(double r,double i);
          	double getReal();
          	double getImag();
      };
      void Complex::init(double r,double i){
          real = r;
          imag = i;
      }
      void Complex::getReal(){
          return real;
      }
      void Complex::getImag(){
          return imag;
      }
      
  • const(常量)成員函數

    為了禁止成員函數修改數據成員的值,可以將它設置為const(常量)成員函數。設置的方法是在成員函數形參列表的後面加上關鍵字const,格式如下:

    class X{
        T f(T1,T2,...) const;
    };
    

    說明:T是函數返回類型,f是函數名,T1T2是各參加的類型。將成員函數設置為const類型後,表明該成員函數不會修改任何成員的值。

    注意:只有類的成員函數才能指定為常量,一般的函數是一能的。const成員函數與const參數是不同的。

  • 成員函數的重載與默認實參

    類的函數是可以重載,也可以指定默認實參。

    在外定義的函數,只能在聲明時或類外定義成員函數時才能指定默認實參,但不能在聲明和定義中同時指定。

嵌套類型

嵌套類型是在類中定義的類、枚舉、使用typedef聲明為成員的任意類型以及使用using聲明的類型別名。

  • 嵌套類

    • 定義在另一個類的內部的類稱作嵌套類,嵌套類也是一個獨立的類,與外層類基本沒有關係;
    • 外層類的對象和嵌套類的對象是相互獨立的,嵌套類對象中不包含任何外層類定義的成員,外層類也不包含嵌套類定義的成員;
    • 嵌套類的訪問許可權由外層類決定;
    • 外層類對嵌套類的成員沒有特殊的訪問許可權,嵌套類對外層類的成員也沒有訪問許可權;
    class X{
        ...
            class Y{       //Y是在X類定義的嵌套類
                ...
            }
    };
    
    • 嵌套類也可以在類內聲明,類外定義(需要外層類類型來限定)。
    class X{
          ...
          public:
           	class Y;      //Y是X的嵌套類,定義在外層類之外
     };
     class X::Y{          //Y是在X類外定義的嵌套類
         ...
     }
    
  • 類型別名

    在類內部可以使用typedefusing聲明類型別名。

    typedef T alias;
    using alias = T;
    

類類型與對象

通過class定義的類型稱為類類型,由類類型定義的變數稱為對象。

類類型

不同類類型的對象不能進行自動相互轉換,即使兩個類具有完全相同的成員列表,它們也是不同類型,是不能進行自動類型轉換。

可以直接把類名作為類型的名字來用,從而直接指向類類型。也可以把類名跟關鍵字後面來使用。

Complex c;         //默認初始化Complex類型的對象
class Complex c;   //等價聲明

類的聲明和定義是可以分開的,可以先聲明類,而暫時不定義它。

class C;   //C類的聲明

對象

類是對同類事物的一種抽象,這類事物中具體的一個實例就把它看作一個對象。類和對象的關係就是數據類型和變數的關係。

  • 對象的定義

    用類定義對象的形式如下:

    類類型名 對象名;
    

    類類型是一種自定義類類型,可以定義類型的變數,也可以定義類類型的指針和引用。

    Clock* p = &cl1;   //定義Clock類的指針p指向對象cl1
    Clock& r = cl2;    //定義Clock類的引用r指向對象cl2
    
  • 對象對成員的訪問

    類中成員之間可以相互訪問,不受訪問說明符的限制,可以直接使用成員名。類外使用只能使用「對象名.成員名」訪問具有public訪問說明符的成員。對象引用方法與結構相似,必須用成員運算符「.」作為對象名和對象成員之間的間隔符,格式如下:

    對象名.數據成員名
    對象名.成員函數名(實參列表)
    clk1.setHour(12);
    clk1.print();
    

    說明:類外只能訪問對象的公有成員,不能訪問對象的私有和受保護成員;如果定義的對象指針,在通過指針訪問對象成員時,要用成員運算符「->」作為指針對象和對象成員之間的間隔符。

  • 對象間的賦值

    不同類類型的對象之間不能互相賦值。同類的不同對象之間,以及同類的指針之間可以相互賦值。

    對象名1 = 對象名2;
    

    說明:進行賦值兩個對象類型必須相同;進行數據成員的值複製,賦值之後,兩不相干。


Tags: