一、類聲明
//類是一種使用者自訂類型,聲明形式:
class 類名稱
{
public:
公有成員(外部介面)
private:
私人成員
protected:
保護成員
};
在關鍵字public後面聲明,它們是類與外部的介面,任何外部函數都可以訪問公有類型資料和函數。
在關鍵字private後面聲明,只允許本類中的函數訪問,而類外部的任何函數都不能訪問。
在關鍵字protected後面聲明,與private類似,其差別表現在繼承與派生時對衍生類別的影響不同。
C++ Code
1 2 3 4 5 6 7 8 9 10 11
|
|
class Clock { public: void Display(); void Init(int hour, int minute, int second);private: int hour_; int minute_; int second_; }; |
假設定義了一個Clock 類,因為成員是private的,那麼 Clock ck; ck.hour_ = 12; 是錯誤的,對此定義一個public 的void SetHour(int hour) 來設定hour_ 的值。
二、內聯成員函數、成員函數的重載及其預設參數
在這裡有內嵌函式的概念。成員函數也可以是內聯的,若在類內部實現,inline 關鍵字可加可不加;在類外部實現,需加inline,
如 inline void Clock::SetHour(int hour) { } 。實際上即使加了inline也不一定宏展開,比如遇到switch,for 語句的時候就往往不會。
此外,成員函數也像一般函數那樣可以重載,也可以有預設參數,參考這裡。
三、類與結構體
class與struct的區別:在未指定存取權限時,class預設的是私人的,struct預設是公有的,
struct Test
{
int X;//公有的
...
};
此外,Test 可以獨立作為一個tag,而不像C語言那樣需要 struct Test 作為一個類型。
四、隱含的 this 指標
成員函數有一個隱含的附加形參,即指向該對象的指標,這個隱含的形參叫做this指標(編譯器自動傳遞)
使用this指標保證了每個對象可以擁有不同數值的資料成員,但處理這些成員的代碼可以被所有對象共用
成員函數是唯讀代碼,由所有對象共用,並不佔對象的儲存空間,因為this指標指向當前對象,所以成員函數可以區分它所作用的對象是哪一個。
五、類範圍、前向聲明
(1)、每個類都定義了自己的範圍稱為類範圍,類範圍中說明的標識符只在類中可見。除了類範圍,還有塊範圍、檔案範圍、函數原型範圍、函數範圍,舉個例子:
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
|
#include <iostream> using namespace std;class Test { public: int num_; }; //num_ = 20; Error,num_的範圍在類內部 int num_ = 20; // num_的範圍是檔案範圍,與類中的num_是不同的範圍
int add(int a, int b); // a, b兩個標識符的範圍為函數原型範圍
int main(void) { int num_ = 30; // num_為塊作域 { int num_ = 100; // num_為塊作域 } cout << num_ << endl; cout <<::num_ << endl; return 0; } int add(int a, int b) // 形參a與b也算是塊範圍 { return a + b; } int test() { LABEL1: //函數範圍 cout << "label1" << endl; goto LABEL3; LABEL2: cout << "label2" << endl; goto LABEL1; LABEL3: cout << "label3" << endl; goto LABEL2; } |
(2)、C++中類必須先定義,才能夠執行個體化。兩個類需要相互引用標頭檔形成一個“環形”引用時會出錯。這時候需要用到前向聲明,前向聲明的類不能執行個體,但可以定義指標或引用。
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
|
#ifndef _B_H_ #define _B_H_class A; class B { public: B(void); ~B(void); void fun(A &a) { } A *a_; // 前向聲明的類不能執行個體化對象 }; #endif // _B_H_ |
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
|
#ifndef _A_H_ #define _A_H_#include "B.h" class A { public: A(void); ~A(void); B b_; }; #endif // _A_H_ |
六、嵌套類、局部類
(1)、嵌套類
外圍類需要使用嵌套類對象作為底層實現,並且該嵌套類只用於外圍類的實現,且同時可以對使用者隱藏該底層實現。
從範圍的角度看,嵌套類被隱藏在外圍類之中,該類名只能在外圍類中使用。如果在外圍類之外的範圍使用該類名時,需要加名字限定。
嵌套類中的成員函數可以在它的類體外定義。
嵌套類的成員函數對外圍類的私人成員沒有訪問權,反之亦然。
嵌套類僅僅只是文法上的嵌入
(2)、局部類
類也可以定義在函數體內,這樣的類被稱為局部類(loacl class)。局部類只在定義它的局部域內可見。
局部類的成員函數必須被定義在類體中。
局部類中不能有靜態成員,關於類中的靜態成員和靜態成員函數以後再談。
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
|
#include <iostream> using namespace std;class Outer { public: class Inner { public: void Fun(); //{ // cout<<"Inner::Fun ..."<<endl; //} }; public: Inner obj_; void Fun() { cout << "Outer::Fun ..." << endl; obj_.Fun(); } }; void Outer::Inner::Fun() { cout << "Inner::Fun ..." << endl; } void Fun() { class LocalClass { public: int num_; void Init(int num) { num_ = num; } void Display() { cout << "num=" << num_ << endl; } //static int num2_; // 局部類內部不能定義靜態成員 }; LocalClass lc; lc.Init(10); lc.Display(); } int main(void) { Outer o; o.Fun(); Outer::Inner i; i.Fun(); Fun(); //LocalClass lc; Error,局部類只能在定義它的函數體中使用 return 0; } |
七、PIMPL 技法
來看下面的樣本:
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
|
// file y.h #include "x.h“ class Y { void Fun(); X x_;}; // file y.cpp #include “y.h” void Y::Fun { return x_.Fun(); } // file main.cpp #include “y.h” int main(void) { Y y; y.Fun(); } |
上面程式存在的問題是:
1、引入更多的標頭檔,降低編譯速度
2、在編譯期如果X的大小改變了,y.cpp 和 main.cpp 都得重新編譯;在運行期,如果X有子類,也不能使用多態虛函數。
3、假設y.cpp 編譯成動態庫給main.cpp 使用,當X的大小變化,動態庫需要重新編譯,此時main.cpp 因為有定義對象y ,故也需要
重新編譯。
下面介紹一種PIMPL 技法,有人也把它當作一種設計模式:
PIMPL(private implementation或pointer to implementation)也稱為handle/body idiom
PIMPL背後的思想是把客戶與所有關於類的私人部分的知識隔離開。避免其它類知道其內部結構
降低編譯依賴、提高重編譯速度
介面和實現分離
降低模組的耦合度
編譯期
運行期
提高了介面的穩定程度
對於庫的使用,方法不能改變
對於庫的編譯,動態庫的變更,客戶程式不用重新編譯
修改後的程式:
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
|
// file y.h class X; class Y { Y(); ~Y(); void Fun(); X *px_; }; // file y.cpp #include "x.h" Y::Y() : px_( new X ) {} Y::~Y() { delete px_; px_ = 0; } void Y::Fun() { return px_->Fun(); } // file main.cpp #include “y.h” int main(void) { Y y; y.Fun(); } |
即Y 內部成員是X* 指標,在32位系統上,指標大小固定為4個位元組,即使X大小改變,也不影響Y。如果X 有子類,通過基類指標px_
還可以實現虛函數多態。
參考:
C++ primer 第四版
Effective C++ 3rd
C++編程規範