C++有三種訪問控制符號:public,protect,private,
同時,也有三種繼承方式:public,protect,private。
訪問控制
訪問控制是對類成員而言的,對非類成員而言,訪問控制是不適用的。
在Java,C#中,也有訪問控制的概念,不過Java和C#中,訪問控制的用法與C++不用:
class Foo { // C++支持這種形式 public: int a; };
class Foo { // C#支持這種形式 public int a; }
public
木有任何限制
private
只能被類聲明中的成員函數和友元訪問。
注意~這里是“類聲明中”而不是“實例中”,同一個類的不同實例,是可以互訪private成員的,下文的protect也類似:
#include <iostream> class Foo { private: int _val; public: Foo(int val): _val(val){}; int GetValue(Foo& foo) { // 訪問private成員 return foo._val; } }; int main(void) { Foo foo1(1); Foo foo2(2); std::cout << foo1.GetValue(foo1) << std::endl;
// foo1訪問了foo2的private成員,跨實例訪問 std::cout << foo1.GetValue(foo2) << std::endl; }
private的另一個用途是禁用編譯器自動生成的代碼。對於一個類,編譯器自動構造3個玩意:
默認構造函數、默認復制構造函數、默認賦值函數,如果不想讓編譯器生成這3個玩意,需要顯式將之設置為private屬性~:
#include <iostream> class FooA { public: int value; }; int main(void) { using namespace std; // 調用了編譯器生成的默認構造函數 FooA fooA1; fooA1.value = 5; // 調用了編譯器默認生成的復制構造函數 FooA fooA2 = fooA1; fooA1.value = 10; FooA fooA3; // 調用了編譯器默認生成的賦值函數 fooA3 = fooA1; cout << fooA1.value << fooA2.value << fooA3.value << endl; system("pause"); }
#include <iostream> class FooB { public: int value; FooB(int v):value(v){}; // 通過private禁用了以下3個玩意 private: FooB(); FooB(FooB&); FooB& operator=(FooB&); }; int main(void) { using namespace std; // 禁用了默認構造函數: // error C2248: “FooB::FooB”: 無法訪問 private 成員(在“FooB”類中聲明) // FooB fooB1; FooB fooB1(0); fooB1.value = 5; // 禁用了復制構造函數 // error C2248: “FooB::FooB”: 無法訪問 private 成員(在“FooB”類中聲明) // FooB fooB2 = fooB1; fooB1.value = 10; FooB fooB3(0); // 禁用了賦值運算符 // error C2248: “FooB::operator =”: 無法訪問 private 成員(在“FooB”類中聲明) // fooB3 = fooB1; //cout << fooB1.value << fooB2.value << fooB3.value << endl; system("pause"); }
protect
如果不考慮繼承,protect和private完全一樣。但是在繼承中,protect就有了各種奇葩的表現。
繼承訪問控制
在繼承中,可以指定繼承方式,繼承方式和上述的訪問控制相結合,用以派生類中基類成員的訪問控制。
繼承訪問控制和基類成員的訪問控制的結合,有如下規律——“從嚴控制”,顯然,由寬松至嚴格的順序為:
public>protect>private
public繼承
最寬松的繼承,基類成員的訪問控制不變~
protect繼承
基類的