成員存取控制 (C++)
存取控制可讓您將類別的介面與 private
實作詳細資料和 protected
僅供衍生類別使用的成員區隔 public
開。 除非發現下一個存取規範,否則存取規範會套用至在其後宣告的所有成員。
class Point
{
public:
Point( int, int ) // Declare public constructor.;
Point();// Declare public default constructor.
int &x( int ); // Declare public accessor.
int &y( int ); // Declare public accessor.
private: // Declare private state variables.
int _x;
int _y;
protected: // Declare protected function for derived classes only.
Point ToWindowCoords();
};
預設存取權位於 private
類別中,以及 public
結構或等位。 您可以依任意順序使用類別中的存取規範任何次數。 類別類型物件的儲存體配置與實作相關。 不過,編譯器必須保證將成員指派給存取規範之間連續較高的記憶體位址。
成員存取控制
存取的類型 | 意義 |
---|---|
private |
宣告為 的 private 類別成員只能由 類別的成員函式和 friend(類別或函式)使用。 |
protected |
宣告為 的 protected 類別成員可由 類別的成員函式和 friend(類別或函式)使用。 此外,類別所衍生的類別也可以使用這些類別成員。 |
public |
宣告為 的 public 類別成員可供任何函式使用。 |
存取控制可協助防止您使用物件的方式使用物件。 當您進行明確的類型轉換時,就會遺失此保護。
注意
存取控制同樣適用於所有名稱:成員函式、成員資料、巢狀類別及列舉程式。
衍生類別中的存取控制
在衍生類別中可存取哪些基底類別的成員是由兩個因素所控制,這些相同的因素可控制在衍生類別中對於繼承成員的存取:
衍生類別是否使用
public
存取規範宣告基類。要存取哪些基底類別的成員。
下表顯示這些因素之間的互動,以及如何判斷基底類別成員存取。
基底類別中的成員存取
private |
protected |
public |
---|---|---|
任何衍生存取一律無法存取 | private 如果您使用衍生,則為 private 衍生類別中的 |
private 如果您使用衍生,則為 private 衍生類別中的 |
protected 如果您使用衍生,則為 protected 衍生類別中的 |
protected 如果您使用衍生,則為 protected 衍生類別中的 |
|
protected 如果您使用衍生,則為 public 衍生類別中的 |
public 如果您使用衍生,則為 public 衍生類別中的 |
下列範例說明存取衍生:
// access_specifiers_for_base_classes.cpp
class BaseClass
{
public:
int PublicFunc(); // Declare a public member.
protected:
int ProtectedFunc(); // Declare a protected member.
private:
int PrivateFunc(); // Declare a private member.
};
// Declare two classes derived from BaseClass.
class DerivedClass1 : public BaseClass
{
void foo()
{
PublicFunc();
ProtectedFunc();
PrivateFunc(); // function is inaccessible
}
};
class DerivedClass2 : private BaseClass
{
void foo()
{
PublicFunc();
ProtectedFunc();
PrivateFunc(); // function is inaccessible
}
};
int main()
{
DerivedClass1 derived_class1;
DerivedClass2 derived_class2;
derived_class1.PublicFunc();
derived_class2.PublicFunc(); // function is inaccessible
}
在 中 DerivedClass1
,成員函式 PublicFunc
是成員 public
,而且 ProtectedFunc
是成員, protected
因為 BaseClass
是 public
基類。 PrivateFunc
是 private
, BaseClass
而且無法存取任何衍生類別。
在 中 DerivedClass2
,函式 PublicFunc
和 ProtectedFunc
會被視為 private
成員,因為 BaseClass
是 private
基類。 同樣地, PrivateFunc
是 private
, BaseClass
而且無法存取任何衍生類別。
您可以在未使用基底類別存取指定名稱的情況下宣告衍生類別。 在這種情況下,如果衍生類別宣告使用 class
關鍵字,則會考慮 private
衍生。 如果衍生類別宣告使用 struct
關鍵字,則會考慮 public
衍生。 例如,下列程式碼:
class Derived : Base
...
等於:
class Derived : private Base
...
同樣地,下列程式碼:
struct Derived : Base
...
等於:
struct Derived : public Base
...
宣告為具有 private
存取權的成員無法存取函式或衍生類別,除非這些函式或類別是使用 friend
基類中的宣告來宣告。
類型 union
不能有基類。
注意
指定 private 基類時,建議明確使用 private
關鍵字,讓衍生類別的使用者瞭解成員存取權。
存取控制和靜態成員
當您將基類指定為 private
時,它只會影響非靜態成員。 在衍生類別中仍然可以存取公用的靜態成員。 不過,使用指標、參考或物件來存取基類的成員,可能需要轉換,以再次套用存取控制。 請考慮下列範例:
// access_control.cpp
class Base
{
public:
int Print(); // Nonstatic member.
static int CountOf(); // Static member.
};
// Derived1 declares Base as a private base class.
class Derived1 : private Base
{
};
// Derived2 declares Derived1 as a public base class.
class Derived2 : public Derived1
{
int ShowCount(); // Nonstatic member.
};
// Define ShowCount function for Derived2.
int Derived2::ShowCount()
{
// Call static member function CountOf explicitly.
int cCount = ::Base::CountOf(); // OK.
// Call static member function CountOf using pointer.
cCount = this->CountOf(); // C2247: 'Base::CountOf'
// not accessible because
// 'Derived1' uses 'private'
// to inherit from 'Base'
return cCount;
}
在上述程式碼中,存取控制項禁止從 Derived2
的指標轉換為 Base
的指標。 指標 this
隱含的類型 Derived2 *
為 。 若要選取函 CountOf
式, this
必須轉換成 類型 Base *
。 不允許這類轉換,因為 Base
是 private 的 Derived2
間接基類。 只有直接衍生類別的指標可以接受轉換成 private 基類類型。 這就是為什麼型 Derived1 *
別的指標可以轉換成 型別 Base *
。
未使用指標、參考或物件來選取函式的 CountOf
明確呼叫,表示沒有轉換。 這就是允許呼叫的原因。
衍生類別 T
的成員和朋友可以將指標 T
轉換成 的直接基類 T
指標 private 。
存取虛擬函式
套用至 virtual
函式的存取控制是由用來進行函式呼叫的類型所決定。 覆寫函式的宣告不會影響指定類型的存取控制。 例如:
// access_to_virtual_functions.cpp
class VFuncBase
{
public:
virtual int GetState() { return _state; }
protected:
int _state;
};
class VFuncDerived : public VFuncBase
{
private:
int GetState() { return _state; }
};
int main()
{
VFuncDerived vfd; // Object of derived type.
VFuncBase *pvfb = &vfd; // Pointer to base type.
VFuncDerived *pvfd = &vfd; // Pointer to derived type.
int State;
State = pvfb->GetState(); // GetState is public.
State = pvfd->GetState(); // C2248 error expected; GetState is private;
}
在上述範例中,使用類型 VFuncBase
呼叫 VFuncDerived::GetState
的指標呼叫虛擬函 GetState
式,並將 GetState
視為 public
。 不過,使用 型別指標呼叫 GetState
是存取控制違規,因為 GetState
是在 類別 VFuncDerived
中宣告 private
。 VFuncDerived
警告
虛擬函式 GetState
可以使用基底類別 VFuncBase
的指標呼叫。 這並不表示所呼叫的函式是該函式的基類版本。
具有多重繼承的存取控制
在包含虛擬基底類別的多重繼承斜格紋中,可以透過多個路徑存取指定的名稱。 由於可以依循這些不同路徑套用不同的存取控制,編譯器會選擇授予較多存取權的路徑。 請參閱下圖:
下圖顯示下列繼承階層:類別 VBase 是基類。 Class LeftPath 會使用虛擬 private VBase 繼承自 VBase。 類別 RightPath 也會繼承自 VBase,但使用虛擬 public VBase。 最後,衍生類別繼承自使用 public LeftPath、 public RightPath 的 LeftPath 類別和 Class RightPath。
依序繼承圖形的路徑進行存取
在圖中,類別 VBase
中宣告的名稱一定會透過類別 RightPath
進行存取。 正確的路徑更容易存取,因為 RightPath
宣告 VBase
為 public
基類,同時 LeftPath
宣告 VBase
為 private
。
另請參閱
意見反映
https://aka.ms/ContentUserFeedback。
即將推出:我們會在 2024 年淘汰 GitHub 問題,並以全新的意見反應系統取代並作為內容意見反應的渠道。 如需更多資訊,請參閱:提交及檢視以下的意見反映: