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繼承
基類的
