C++筆記 --- 類與結構


 

目錄

結構體

﹡類 -- 訪問修飾符
﹡類 -- 成員函數
﹡類 -- 成員變量
﹡類 -- 操作符重載
﹡類 -- 友元類
﹡類 -- 抽象類
﹡類 -- 例程(匿名對象的調用,函數對象,單例模式)

 (本章節中例子都是用 VS2005 編譯調試的)


 

結構體

聲明形式:

struct 結構體名{

  成員聲明;

  成員函數聲明;

};

定義:

在c++允許聲明結構體變量時省關鍵字struct(struct inflatable goose等價於inflatable goose)

成員訪問修飾符:

  • private
  • protected
  • public

說明:

  • 結構體可以擁有成員函數,可以擁有析構函數和構造函數,但是默認訪問權限是public的,用法和class相同
  • 在結構體定義完后要加‘;’
  • 引用結構體成員時,如果成員本身屬於一個結構體,須一級一級找出最低級成員
  • 結構體類似 類 ,只是類的默認成員訪問修飾符是 private 而結構體是 public,結構體也可以繼承與另一個結構體,

引用方式:

  • 結構體變量名 . 成員名(或者成員函數名)
  • 結構體變量指針 -> 成員名(或者成員函數名)
  • (*結構體變量指針) . 成員名(或者成員函數名)
struct 結構體內存分配原理(class類似):
對應知識點:
1.內存對齊:
CPU 每次都是從以2字節(16位CPU)或是4字節(32位CPU)的整數倍的內存地址中讀進數據的.所以編譯器為了優化代碼,往往會根據變量的大小,將其指定到合適的位置,即稱為內存對齊.內存對齊主要是為讓 CPU 在讀取數據減少其操作次數的時候
2.結構體內存分配的規則:
1.結構體每個成員相對於結構體首地址的偏移量(offset)都是(這個)成員大小的整數倍,如有需要編譯器會在成員之間加上填充字節(internaladding);
2.結構體的總大小為結構體最寬基本類型成員大小的整數倍,如有需要編譯器會在最末一個成員之后加上填充字節(trailingpadding);

例子:

簡單聲明和訪問結構體變量成員:

View Code
 1 #include <iostream>
 2 #include <string>
 3 using namespace std;
 4 
 5 struct person
 6 {
 7     string name;
 8     bool sex;
 9     int age;
10     person(string n,bool s,int a)
11     {
12         name = n;
13         sex = s;
14         age = a;
15     }
16     person()
17     {
18         name = "";
19         sex = 0;
20         age = 0;
21     }
22     void showinfo()
23     {
24         cout<<"名字為: "<<name<<";  性別為: "<<(sex?"":"")<<";  年齡為: "<<age<<endl;
25     }
26 };
27 
28 void main()
29 {
30     person lisi("李四",0,18);
31     person *plisi = &lisi;
32     
33     //結構體變量訪問成員的方法:
34     lisi.showinfo();
35     //指針的兩種訪問成員的方法;
36     plisi->showinfo();
37     (*plisi).showinfo();
38     
39     //修改結構體成員方法后的
40     lisi.age = 40;
41     lisi.showinfo();
42 
43     system("pause");
44 }
45 /***************************************
46 輸出結果:
47 名字為: 李四;  性別為: 男;  年齡為: 18
48 名字為: 李四;  性別為: 男;  年齡為: 18
49 名字為: 李四;  性別為: 男;  年齡為: 18
50 名字為: 李四;  性別為: 男;  年齡為: 40
51 請按任意鍵繼續. . .
52 ****************************************/

結構體成員為結構體的聲明和訪問其方法:

View Code
 1 struct CPU
 2 {
 3     string type;
 4     int price;
 5 };
 6 struct memory
 7 {
 8     string type;
 9     int price;
10 };
11 struct mainboard
12 {
13     string type;
14     int price;
15 };
16 struct computer
17 {
18     // 結構體中聲明結構體變量
19 
20     CPU cpu;
21     mainboard mb;
22     memory my;
23 };
24 
25 void func()
26 {
27     computer cmpu;
28 
29     //對 cmpu 結構體中的 cpu, mb , my 結構體變量賦值
30     cmpu.cpu.price = 740;
31     cmpu.cpu.type = "Intel 酷睿i3";
32     cmpu.mb.price = 130;
33     cmpu.mb.type = "金士頓4GB";
34     cmpu.my.price = 500;
35     cmpu.my.type = "華碩P8H61";
36 }

結構體成員包含成員限制符:

View Code
 1 struct ex
 2 {
 3 private:
 4     string word;
 5 public:
 6     ex()
 7     {
 8         word = "hello!";
 9     }
10     void show()
11     {
12         cout<<word<<endl;
13     }
14 };
15 
16 void func()
17 {
18     ex ex1;
19     ex1.show();
20     ex1.word = "change the word"; //編譯錯誤,因為 word 訪問修飾符為 private
21     system("pause");
22 }

結構體內存對齊

View Code
#include<iostream> 
 
using namespace std; 
struct test1{ 
        char a; 
        double b; 
        char c; 
}; 
struct test2{ 
        char a; 
        int b; 
        char c; 
        char d; 
}; 
struct test3{ 
        char a; 
        char c; 
        char b; 
}; 
int main() 
{ 
        cout<<"the size of test1 is "<<sizeof(test1)<<endl; 
        cout<<"the size of test2 is "<<sizeof(test2)<<endl; 
        cout<<"the size of test3 is "<<sizeof(test3)<<endl; 
        return 0; 
} 

 

 [返回目錄]


 

 

成員訪問權限


分類:

  • private 私有變量和私有函數,其他的外部類,外部函數,派生類都無法訪問這個部分的變量和函數,其只供給本類的成員函數調用和訪問.
  • public 公有變量和公有函數,所有外部函數,派生類,外部類,本類都可以訪問這個部分的變量和函數
  • protected 保護變量和保護函數,對於派生類來說此部分函數和變量是可以調用和訪問的相當於是 public 權限,對於外部類和外部函數來說此部分是不能訪問的相當於 private 權限

 

注意:

  • 對於外部函數來說,protected與private訪問權限一樣
  • 對於派生類來說,protected與public訪問權限一樣

例子:

View Code
 1 // 例1 -- public, private ,protected 對於外部的區別
 2 class A
 3 {
 4 private:
 5     int a;
 6 protected:
 7     int b;
 8 public:
 9     int c;
10 };
11 
12 void func()
13 {
14     A a;
15     a.a = 5; //錯誤, 因為外部函數無法訪問類的 private 成員
16     a.b = 5; //錯誤,因為外部函數無法訪問類的 protected 成員
17     //由此看來對於外部函數來說, private 和 protected 的訪問修飾符的都是禁止外部函數訪問
18     a.c = 5;
19     //而 public 訪問修飾符則是允許外部訪問
20 }
21 
22 
23 // 例2 -- public, private ,protected 對於子類的區別
24 class A
25 {
26 private:
27     int a;
28 public:
29     int b;
30 protected:
31     int c;
32 };
33 class B:public A
34 {
35     void func()
36     {
37         a = 5;//錯誤, 因為子類無法訪問類的 private 成員
38         b = 5;// protected 訪問修飾符允許子類部訪問
39         c = 5;// public 訪問修飾符允許子類訪問
40         //由此看來對於子類來說, public 和 protected 的訪問修飾符的都是允許子類訪問
41     }
42 };

 

成員函數
[隱藏參數 this 指針][用戶自定義成員函數(靜態,非靜態)][構造函數][析構函數][友元函數][虛函數][成員函數屬性]


解釋:

類的成員函數對於類產生的對象來說共用一組成員函數的,但各自有各自的成員變量

隱藏參數 this 指針:

C++ 編譯器為類成員函數多准備了一個隱藏參數(在程序代碼中看不到),舉個例子,假設我們又一個 CMyClass 如下:

// CMyClass.h  ---------------------------
class CMyClass{
private:
    int nCount;
public:
    int getCount();
};

// CMyClass.cpp  -------------------------
int CMyClass::getCount()
{
         return nCount;
}

我們知道 C++ 中 CMyClass 類的所有實例共用成員函數 getCount 那么多個實例在調用 getCount 這個成員函數時候,getCount 就是通過這個隱藏的參數 this 找到正確的 nCount 並返回的(this 為指向實例對象的指針),那么 C++ 編譯器針對 CMyClass::getCount 實際做出來的代碼如下:

int CMyClass getCount((CMyClass*) this)
{
    return this->nCount
}

 那么調用也是一樣的

void func()
{
    CMyClass exp;
    exp.getCount();
    //實際產生出來的效果是把exp的地址傳遞給 CMyClass::getCount 這個函數像這樣: getCount(&exp)
}

當然我們有時候也不想讓 this 這種作為該函數的最后一個參數,那么我們可以采取下面兩個方法:

  • 不要使用類的成員函數
  • 使用 static 成員函數(靜態成員函數),也就是在函數前面加上 static 關鍵字

用戶自定義成員函數:

  • 靜態函數成員:
    • 特點:
      • 靜態成員函數只能訪問靜態成員變量
      • 在靜態成員函數中是不能調用非靜態函數和非靜態成員數據變量
      • 靜態成員函數屬於類本身,在類中加載的時候,即為他們分配了空間
      • 靜態成員和靜態成員函數可以起到於全局變量和全局函數一樣的作用,因此靜態成員函數可以作為窗體編程的回調函數或多線程編程中線程的起始函數
    • 聲明形式(用static聲明的成員函數):
      • 訪問修飾符 static 返回類型 函數名 (形參表);
    • 訪問方式:
      • 類名::函數名(實參表)
      • 實例名.函數名(實參表);
      • 實例指針->函數名(實參表);
  • 非靜態成員函數:
    • 特點:
      • 屬於類的實例,也就是應該先產生對象實例才可以調用類的非靜態成員函數
      • 非靜態成員函數能訪問靜態成員變量與非靜態成員變量
      • 非靜態的成員函數可以調用靜態成員變量和非靜態成員變量和靜態函數
    • 聲明形式:
      • 訪問修飾符 返回類型 函數名(形參表);
    • 訪問方式:
      • 實例名.函數名(實參表);
      • 實例指針->函數名(實參表);
  • 例子:
    靜態函數與非靜態函數訪問成員變量的區別:
    View Code
     1  class A
     2  {
     3  private:
     4      int a;
     5      static int b;
     6  public:
     7      void changeValue()
     8      {
     9          a = 5;
    10          b = 10;
    11      }
    12      static void changeValue2()
    13      {
    14          a = 5;   //錯誤,因為靜態成員方法無法訪問非靜態成員變量
    15          b = 10;
    16      }
    17  };
    靜態函數與非靜態函數的調用區別:
    View Code
     1 class A
     2  {
     3  public:
     4      void show()
     5      {
     6          cout<<"this is not static function!"<<endl;
     7      }
     8      static void show2()
     9      {
    10          cout<<"this is static function!"<<endl;
    11      }
    12  };
    13  void main()
    14  {
    15      A a;
    16      A::show2();
    17      A::show();    //錯誤,因為 A:: 后只能跟靜態成員方法
    18      a.show();
    19      a.show2();
    20      system("pause");
    21  }
    成員函數指針:
    View Code
    #include <iostream>
    using namespace std;
    
    class test 
    {
    public:
        static void sfunc(){cout<<"static function"<<endl;}
        void nfunc(){cout<<"member function"<<endl;}
        virtual void vfunc(){cout<<"virtual function"<<endl;}
    };
    
    int main()
    {
        test a;
        void (*ps)() = &test::sfunc;
        void (test::*pn)() = &test::nfunc;
        void (test::*pv)() = &test::vfunc;
    
        ps();
        (a.*pn)();
        (a.*pv)();
    
        system("pause");
        return 0;
    }
    /******************************************
    輸出結果:
    static function
    member function
    virtual function
    請按任意鍵繼續. . .
    ******************************************/

構造函數:

  • 由用戶定義:    由系統調用完成對對象的初始化,且在其完成工作前對象是不存在的
  • 默認構造函數:    未提供顯示初始化值時被用創建對象的構造函數
  • 調用方式:
    • 顯示調用格式:    類名 對象名 = (形參列表);
    • 隱示調用格式:    類名 對象名 (形參列表);
    • 調用默認構造函數:  類名 對象名;
  • 注意:
    • 要創建對象而不顯示地初始化則必須定義一個不接受任何參數的默認構造函數
    • 在構造函數中使用new來初始化指針(指向對象),則應在析構函數中使用delete
    • 如果有多個構造函數,則必須以相同的方式使用new,因為只有一個析構函數,不過可以在一個構造函數中使用new來初始化指令,而另一個構造函數中將該指令初始化為null或0,因為delete可作用與空指針
    • 用new開辟對象, 格式:
      •  類名 *指針名 = new 類名(形參表);
      •  類名 *指針名 = new 類名();   //調用默認構造函數
  • 例子:
    View Code
     1 // 例1 ---  調用構造函數
     2 class A
     3 {
     4 private:
     5     int a;
     6 public:
     7     A(int b):a(b){}
     8     //這種形式等價於 A(int b){ a = b;}
     9     A(){ a = 5;};
    10     void show(){cout<<"the value of a is: "<<a<<endl;}
    11 };
    12 void func()
    13 {
    14     A ex0;    // 調用默認構造函數 A();
    15     A ex1(7); // 調用 A(int b)(); 這個構造函數
    16     A ex2 = (8); // 調用 A(int b)(); 這個構造函數
    17 
    18     ex0.show();  
    19     ex1.show();
    20     ex2.show();
    21 }
    22 /******************************************
    23 輸出結果:
    24 the value of a is: 5
    25 the value of a is: 7
    26 the value of a is: 8
    27 請按任意鍵繼續. . .
    28 ******************************************/
    29 
    30 
    31 
    32 // 例2 ---  動態開辟對象實例調用構造函數
    33 class A
    34 {
    35 private:
    36     int a;
    37 public:
    38     A(int b):a(b){}
    39     //這種形式等價於 A(int b){ a = b;}
    40     A(){ a = 5;};
    41     void show(){cout<<"the value of a is: "<<a<<endl;}
    42 };
    43 void func()
    44 {
    45     A* ex0 = new A();    // 等價於 A* ex0 = new A;   調用默認構造函數 A();
    46     A* ex1 = new A(7); // 調用 A(int b)(); 這個構造函數
    47 
    48     ex0->show();  
    49     ex1->show();
    50 }
    51 /******************************************
    52 輸出結果:
    53 the value of a is: 5
    54 the value of a is: 7
    55 請按任意鍵繼續. . .
    56 ******************************************/

析構函數:

  • 定義:    由用戶定義,卻在對象生存周期即將結束時由系統自動調用
  • 格式:    ~ 類名();
  • 說明:    析構函數無返回值,無聲明類型,無參數
  • 例子:
    View Code
    1 class A
    2 {
    3 private:
    4     int* a;
    5 public:
    6     A(){ a = new int(5);} //作用: 開辟一個整形變量
    7     ~A(){delete a;} //作用: 釋放一個動態開辟的整形變量內存
    8 };

友元函數:

  • 說明:  在類型聲明中將原型放入並在原型聲明前加上關鍵字friend,但不要在定義時加上關鍵字friend,它的訪問權限與類的成員函數的訪問權限相同<聲明而已為private,public,protect>
  • 作用:  把其他類中函數作為自己的友員成員函數,讓特定的類成員成為另一個類的友元函數,而不必讓整個類成為友元,但在使用時,必須小心排列各種聲明和定義順序(且需用到向前聲明)
  • 向前聲明格式:
    • class 類名 ;//向前聲明本類
    • class 所用到的友員成員函數的類的類名 {....};//友元函數類的定義
    • class 類名 {…}//本類的定義
  • 注意:  友元函數不要在類的內部定義,不然編譯不會通過
  • 例子:

友元函數(內部定義):

View Code
 1 class Point  {  
 2 public: 
 3     Point(double xx, double yy)
 4     {
 5         x=xx;
 6         y=yy;
 7     } 
 8     friend void Getxy(Point &a){  cout<<"position is: ("<<a.x<<","<<a.y<<")"<<endl;}
 9 private: 
10     double x, y;  
11 };

友元函數(外部定義):

View Code
 1 class Point  {  
 2 public: 
 3     Point(double xx, double yy)
 4     {
 5         x=xx;
 6         y=yy;
 7     } 
 8     friend void Getxy(Point &a);  
 9 private: 
10     double x, y;  
11 }; 
12 void Getxy(Point &a) 
13 {  
14     cout<<"position is: ("<<a.x<<","<<a.y<<")"<<endl;
15 } 

友元成員函數:

View Code
 1  class Date;                               //對 Date 類的向前聲明
 2  class Time                                //定義 Time 類
 3  {
 4  public:
 5      Time(int,int,int);
 6      void display(Date&);                 //display 是 Time 類的成員函數,形參是 Date 類對象的引用
 7  private:
 8      int hour;
 9      int minute;
10      int sec;
11  };
12  class Date
13  {
14  public:
15      Date(int,int,int);
16      friend void Time::display(Date&);               //聲明 Time 類的 display函數為本類的友元函數
17  private:
18      int month;
19      int day;
20      int year;
21  };
22  Time::Time(int h,int m,int s)                        //定義 Time 類的構造函數
23  {
24      hour = h;
25      minute = m;
26      sec = s;
27  }
28  void Time::display(Date&d)                 //display 函數的作用是輸出年、月、日和時、分、秒
29  {
30      cout<<d.month<<"/"<<d.day<<"/"<<d.year<<endl;       //引用 Date 類對象中的私有數據
31      cout<<hour<<":"<<minute<<":"<<sec<<endl;             //引用本類對象中的私有數據
32  }
33  Date::Date(int m,int d,int y)                        //定義 Date 類的構造函數
34  {
35      month = m;
36      day = d;
37      year = y;
38  }
39 /*
40 請注意本程序的主函數中調用友元函數訪問有關類的私有數據的方法:
41 1、在函數名 display 的前面要加 display 所在的對象名(t1);
42 2、display 成員函數的實參是 Date 類對象 d1,否則就不能訪問 d1 中的私有數據;
43 3、在 Time::display 函數中引用 Date 類私有數據時必須加上對象名,如 d.month 。
44 */

虛函數:

  • 作用:  如果想通過指向派生類對象的基類指針,調用派生類中覆蓋的成員函數,可以用虛函數的方法讓派生類中覆蓋的成員函數被調用
  • 格式:  virtual 返回類型 函數名 (形參表);
  • 注意事項:
    • 如果定義的類作為基類,則應將那些要在派生類中重新定義的類的方式聲明為虛擬的
    • 如果使用指向對象的引用或指針調用虛方法,程序將使用做為對象類型的定義方法而不是使用做為了引用或指針定義的方法
  • 工作原理:[詳細介紹]
    • 給每個對象添加一個隱藏成員,隱藏成員中保存了個指 向函數的地址數組的指針,這種數組稱為虛函數表(vtbl)虛函數表中存儲了為類對象進行聲明的虛函數地址,派生類對象將包含一個指向獨立地址的表指針,如果派生類提供了虛函數的新的定義,該虛函數地址被添加到vtbl中,注意,無論類中包含的虛函數是1還是10個都只需在對象中添加一個地址成員,只是表大小不同而已
  • 純虛函數:
    • 格式:    virtual 函數類型 函數名(形參表)=0;<無函數體>
    • 作用:    有時,要在基類中不能給出虛函數實現代碼,這是可將這種虛函數聲明為純虛函數
    • 注意:    有純虛函數的類都是抽象類,並且抽象類是不能產生實例的.
  • 虛函數使用總結(摘抄於<<深入淺出MFC>>)
    • 如果你期望派生類從新定義一個成員函數,那么你應該在基類中把此函數設置為 virtual
    • 以單一指令調用不同函數,這種性質稱為 Polymorphism(多態)
    • 虛擬函數是 C++ 語言的 Polymorphism 性質以動態綁定的關鍵
    • 既然抽象類中的虛函數不打算被調用,我們就不應該定義它,應該把它設置為純虛函數(在函數聲明后加 "=0" 即可)
    • 我們可以說,擁有純虛函數者為抽象類(abstract class),以別於所謂的具體類(concrete class)
    • 抽象類不能產生實例,但我們可以擁有抽象類的指針,以便於操作抽象類的各個派生類
    • 虛函數派生下去的仍然為虛函數,而且可以省去 virtual 關鍵字
  • 例子:

虛函數:

View Code
 1 class A        //有虛函數的基類
 2 {
 3 public:
 4     virtual void show(){cout<<"這是基類的 A !"<<endl;}
 5     //用虛函數聲明 show 函數
 6 };
 7 class B:public A
 8 {
 9 public:
10     void show(){cout<<"這是派生類 B !"<<endl;}
11 };
12 
13 class C        //沒有虛函數的基類
14 {
15 public:
16     void show(){cout<<"這是基類 C !"<<endl;}
17 };
18 class D:public C
19 {
20 public:
21     void show(){cout<<"這是派生類 D !"<<endl;}
22 };
23 
24 void func( )
25 {
26     A* a = new B;   
27     C* c = new D;   
28     a->show(); //通過虛函數找到子類的成員函數 show
29     c->show(); //沒有虛函數所以只能調用到基類的成員函數 show
30 }
31 /************************************
32 調用 func 函數后的輸出結果:
33 這是派生類 B !
34 這是基類 C !
35 ************************************/

純虛函數:

View Code
 1 class A        //有純虛函數的基類
 2 {
 3 public:
 4     virtual void show() = NULL;
 5     //用純虛函數聲明 show 函數
 6 };
 7 //要注意的是如果類有純虛函數那么這個類無法產生實例,並且純虛函數的必須在其的派生類中實現
 8 class B:public A
 9 {
10 public:
11     void show(){cout<<"這是派生類 B !"<<endl;}//實現基類 A 的純虛函數 show
12 };

利用虛函數/純虛函數,打破子類訪問權限.例子如下:

View Code
#include<iostream>
#include<cstdlib>

using namespace std;

class A{
public:
    virtual void output1() = 0;
    virtual void output2(){cout<<"this is A"<<endl;}
};

class B:public A{
private:
    void output1(){cout<<"this is success!"<<endl;}
protected:
    void output2(){cout<<"this is B"<<endl;}
};

void main()
{
    A* a;
    B b;
    a = &b;

    a->output1();
    a->output2(); //通過 a 我們訪問到了 B 變量 b 的私有成員函數和保護成員函數 output1,output2
    //b.output1(); 
    //b.output2();//這里我們是無權限去訪問類 B 變量 b 的私有成員函數和保護成員函數 output1,output2

    system("pause");
}

 

成員函數屬性:

 函數       能否被繼承   成員還是友員   默認能否生成   能否為虛函數   是否可以有返回值 
構造函數     ×        成員      √       ×        ×
析構函數     ×        成員      √       √        ×
=         ×        成員      √         √        √
&       √        任意      √       √        √
轉換函數    √       成員      ×        √        ×
()       √       成員       ×         √        √
[ ]      √       成員       ×       √        √
→       √       成員       ×       √        √
op =       √       任意       ×       √        √
new      √       靜態成員     ×       ×        void *
delete     √       靜態成員     ×       ×        void
其他操作符   √       任意       ×         √       √
其他成員    √       成員       ×       √       √
友元      ×       友員       ×         ×       √ 

 

成員變量


靜態成員:

  • 無論對象有多少,其共用一份靜態成員,其具有全局性
  • 可以為private,public,protected,且需在外部聲明並且沒有this指針
  • 需要在 cpp 或 .h 中對其進行初始化(格式:    變量類型  類名::靜態變量名 = 初始值; )
  • 靜態成員變量屬於類本身,在類中加載的時候,即為他們分配了空間,所以可以通過((類名.變量名)來訪問.

非靜態成員:

非靜態成員變量屬於類的實例,也就是應該先產生對象實例才會產生類的非靜態成員變量

const成員:

只在調用構造函數時進行賦值,期間不能改動

枚舉成員:

在類中聲明一個枚舉,在類聲明中的這個枚舉的作用域為整個類,因此可以用枚舉為整形提供作用域為整個類的符號名稱,用這種方式聲明枚舉並不會創建數據成員,也就是說,所以對象都不包含枚舉成員

隱藏成員:

  • this指針:
    • 每個對象都有個this指針存放其地址,所以可以用*this引用對象,當成員函數的形參表中的參數與成員變量重名的時候,可以加以區分二者
  • 虛函數表指針:
    • 虛函數指針用於指向虛函數表,位於每個實例對象內存的頭四字節,由於虛函數(Virtual Function)是通過一張虛函數表(Virtual Table)來實現的.簡稱為V-Table.在這個表中,主要是一個類的虛函數的地址表,這張表解決了繼承、覆蓋的問題,保證其真實反應實際的函數.這樣,在有虛函數的類的實例中分配了指向這個表的指針的內存,所以,當用父類的指針來操作一個子類的時候,這張虛函數表就顯得尤為重要了,它就像一個地圖一樣,指明了實際所應該調用的函數

例子:

成員變量:

View Code
 1 class ex
 2 {
 3 private:
 4     enum {Len = 30};    //定義枚舉成員
 5     static const int Len2 = 30;        //定義靜態常量成員, 當然也效果等價於上面的枚舉成員 Len
 6     char member[Len];        //定義非常量常成員
 7     const int constMember;    //定義常量成員
 8     static int staticMember;    //定義靜態成員,若無顯示的初始化,則其值為 0
 9 public:
10     ex(int j = 0,char *pmember = "null" )
11         :constMember(j)        //對常量成員 constMember 的初始化
12     {
13         for(int i=1;i<strlen(pmember);i++)
14             member[i-1] = pmember[i-1];
15     }
16 };
17 int ex::staticMember = 50;    //對靜態成員 staticMember 的顯示初始化

this 指針使用:

View Code
 1 class ex
 2 {
 3 private:
 4     int a;
 5 public:
 6     void changValue(int a)//此時函數參數 a 與成員變 a 重名
 7     {
 8         this->a = a;
 9         //this 代表但前實例的地址,由此可以用此地址調用成員變量即 this->a ,以此區分函數參數 a 與成員變 a
10     }
11 };

 

操作符重載


格式: 

返回類型 operater 操作符(成員列表)

限制:

  • 不能違反操作符原來的語法規則 <例:不能將求模操作% 重載成使用一個操作數>
  • 重載操作符不必是成員函數,但必須有一個操作數為用戶定義類型
  • 不能定義新的操作符
  • 不能重載的操作符
    Ⅰ      sizeof 操作符;
    Ⅱ      . (成員操作符);
    Ⅳ.     *(成員指針操作符);
    Ⅳ      ::(作用解析操作符);
    Ⅴ      ?:(條件操作符);
    Ⅵ      typeid(一個RTTI操作符);
    Ⅶ 強制轉換操作符(const_cast,dynamic,_cast,reinterpret_cast,static_cast)
  • 可被重載的操作符
    + , - , * , / , % , ^ , & , | , ~ , ! , = , > , < , += , -= , /= , %= , ^= , &= , |= , << , >> , >>= , <<= , == , != , <= , >= , && , || , ++ , -- , [] , () , -> , ->* , new , , , new[] , delete , delete[]
  • 只能成員函數重載的操作符:
    • = 賦值操作符
    • ()     函數調用操作符
    • []  下標操作符
    • &rar;∕→* 通過指針訪問類成員操作符

i++,i--,++i,--i 的聲明形式:

  • i++ 為:     返回類型 operator ++(int) {實現體}
  • ++i 為:     返回類型 operator ++()     {實現體}
  • i-- 與 --i 聲明形式同上面相似

例子:

View Code
 1 class CMyString
 2 {
 3 private:
 4     char* m_str;
 5 public:
 6     CMyString(char *str)
 7     {
 8         int size;
 9         size = strlen(str) + 1;
10         m_str= new char[size];
11         strcpy(m_str,str);
12     }
13     CMyString()
14     {
15         m_str = NULL;
16     }
17     ~CMyString()
18     {
19         delete []m_str;
20     }
21     void ShowString()
22     {
23         cout << m_str << endl;
24     }
25     CMyString & operator=(CMyString& mystring)  //運算符重載函數
26     {
27         int size;
28         size = strlen(mystring.m_str) + 1;
29         m_str = new char[size];
30         strcpy(m_str,mystring.m_str);
31         return *this;
32     }
33 };
重載 = 操作符,並含有默認構造參數時候.
#include<iostream>
#include<cstdlib>

using namespace std;

class A{
public:
    A():a(0){};
    A(int argA=0):a(argA){}
    A operator =(A a){return *this;}
public:
    int a;
};

void main()
{
    A a(1);
    A b=a;
    cout<<b.a<<endl;
    //輸出結果為1
    system("pause");
}

 

友元類


聲明:

在類中用 friend class 友元類名;

作用:

在友元類的所有成員函數都可以訪問此類中的所有數據

格式:

  • class 友元類名 ;//向前聲明本類
  • class 擁有友元類的類名{....};//擁有友元類的類的定義
  • class 友元類名 {…}//友元的定義

特點:

  • 友元關系不能被繼承
  • 友元關系是單向的,不具有交換性.若類B是類A的友元,類A不一定是類B的友元,要看在類中是否有相應的聲明.
  • 友元關系不具有傳遞性.若類B是類A的友元,類C是B的友元,類C不一定是類A的友元,同樣要看類中是否有相應的申明

例子:

使用友元類:

View Code
 1 class B;   //友元類的向前聲明
 2 class A    //擁有友元類的類的定義
 3 {
 4     int y;
 5 public:
 6     A()
 7     {
 8         y=4;
 9     }
10     friend B;
11 };
12 
13 class B  //友元類的定義
14 {
15 public:
16     void show(A &a)
17     {
18         cout<<a.y<<endl;
19     }
20 };

多個類包含一個友元類:

View Code
 1 class C;  //友元類的向前聲明
 2 class A   //擁有友元類的類的定義
 3 {
 4     int x;
 5 public:
 6     A()
 7     {
 8         x=4;
 9     }
10     friend C;
11 };
12 
13 class B   //擁有友元類的類的定義
14 {
15     int y;
16 public:
17     B()
18     {
19         y=6;
20     }
21     friend C;
22 };
23 
24 class C    //友元類的定義
25 {
26 public:
27     void show(A &a,B &b)
28     {
29         cout<<a.x<<"  "<<b.y<<endl; 
30     }
31 };
32 
33 void func()
34 {
35     A a;
36     B b;
37     C c;
38     c.show(a,b);
39 }

一個類包含多個個友元類:

View Code
 1 class B;    //友元類向前聲明
 2 class C;    //友元類向前聲明
 3 class A     //擁有友元類的定義
 4 {
 5     int x;
 6 public:
 7     A()
 8     {
 9         x=4;
10     }
11     friend C;
12     friend B;
13 };
14 
15 class B   //友元類的定義
16 {
17 public:
18     void show(A &a)
19     {
20         cout<<"the value of a is: "<<a.x<<"        (in the class B)"<<endl; 
21     }
22 };
23 class C   //友元類的定義
24 {
25 public:
26     void show(A &a)
27     {
28         cout<<"the value of a is: "<<a.x<<"        (in the class C)"<<endl; 
29     }
30 };
31 
32 void func()
33 {
34     A a;
35     B b;
36     C c;
37     b.show(a);
38     c.show(a);
39 } 

 

抽象類


定義:

在類中聲明了純虛方法

注意:

  • 抽象類可以有零個或多個抽象方法,也可以包含非抽象方法
  • 抽象類可以沒有抽象方法,但是有抽象方法的一定是抽象類
  • 抽象方法只涉及聲明不負責實現
  • 抽象類可以派生出子類,子類的非抽象類必須抽象類的方法
  • 抽象類不能創建對象

例子:

1 class A
2 {
3 public:
4    virtual void show() const =0;
5 };

 

 [返回目錄]

例程


匿名對象的調用

View Code
#include <iostream>
#include <cstdlib>
using namespace std;

class test{
private:
    int a;
    int b;
public:
    test(int argA=0,int argB=0):a(argA),b(argB){}
    void output(){cout<<"the a is "<<a<<" ,the b is "<<b<<endl;}
};
void testfun(test arg)
{
    arg.output();
}
void main()
{
    testfun(test(10,5));//創建匿名對象
    system("pause");
}

函數對象

View Code
#include <iostream>
#include <cstdlib>
using namespace std;
int add(int a,int b)
{
    return a+b;
}
int sub(int a,int b)
{
    return a-b;
}
class test{
public:
    int operator ()(int a,int b,int c){return add(sub(a,b),c);}
};

void main()
{
    test t;
    cout<<t(4,2,3)<<endl;
    system("pause");
}

單例模式

View Code
#include<iostream>
using namespace std;

class As
{
public:

    void show()
    {
        cout<<a<<endl;
    }
    static As* getinstance(int a)
    {
        As::a = a;
        return b;
    }
    static void deleteAs()
    {
        delete b;
    }
    virtual ~As()
    {

    }
private:
    static As *b;
    static int a;
    As()
    {
        a=1;
    }
};
As* As::b=new As();
int As::a = 0;
void main()
{
     //靜態成員和成員函數的使用
    As* a = As::getinstance(5);
    a->show();
    delete a;
    if( a == NULL)
        cout<<"a isn't exist!"<<endl;
    else
        cout<<"a is exist!"<<endl;
    a->show();

    system("pause");
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM