寫程序的時候希望一個類能夠訪問另一個類的數據成員(protected, private),例如類A要訪問類B中的數據成員。
1.保持封裝性
可以通過在被訪問的類(B)中定義訪問權限為public的函數,用來返回數據成員的引用。
2.繼承
當一個派生類從父類繼承時,父類的所有成員就成為子類的成員,因此可以將被訪問類作為父類被繼承。要注意此時對父類成員的訪問狀態由繼承時使用的繼承限定符決定。
父類權限 | 繼承方式 | ||
private | protected | public | |
private | private | private | private |
protected | private | protected | protected |
public | private | protected | public |
3.友元
申明要訪問類為被訪問類的友元。例如類A要訪問類B中的數據成員,在B的構造函數加上friend class A; 聲明A是B的友元,可以直接訪問到B中的所有成員。舉個例子就是:
class B { private: int age; protected: int money; public: int gender; B() { age = 20; money = 1000; gender = 1; } friend class C; int getAge(){ return age; } int getMoney(){ return money; } int getGender(){ return gender; } }; class A { public : A() {}; int compute(D &testd) { return ( 25 - testd.age) * testd.money ; } }; int main() { A testa; B testb; testa.compute(testa); /* 輸出結果為(25-20)*1000 */ }
此時B的一個對象作為A某函數成員的形參,原本通過對象是無法訪問到B中的private和protected成員。還可以聲明B作為A的數據成員,這樣也能訪問到B中所有成員。
當使用后一種方法,一個類作為另一個類的數據成員。需要注意:
如果一個類B的對象作為另一個類A的數據成員,則在類A的對象創建過程中,調用其構造函數的過程中,數據成員(類B的對象)會自動調用類B的構造函數。 但應注意:如果類B的構造函數為有參函數時,則在程序中必須在類A的構造函數的括號后面加一“:”和被調用的類B的構造函數,且調用類B的構造函數時的實參值必須來自類A的形參表中的形參。這種方法稱為初始化表的方式調用構造函數。
如:以上面定義的類A為例,在對類A的對象進行初始化時,必須首先初始化其中的子對象,即必須首先調用這些子對象的構造函數。因此,類A的構造函數的定義格式應為:
A:: A(參數表0):成員1(參數表1),成員2(參數表2),…,成員n(參數表n) { ……}
其中,參數表1提供初始化成員1所需的參數,參數表2提供初始化成員2所需的參數,依此類推。並且這幾個參數表的中的參數均來自參數表0,另外,初始化X的非對象成員所需的參數,也由參數表0提供。
在構造新類的對象過程中,系統首先調用其子對象的構造函數,初始化子對象;然后才執行類X自己的構造函數,初始化類中的非對象成員。對於同一類中的不同子對象,系統按照它們在類中的說明順序調用相應的構造函數進行初始化,而不是按照初始化表的順序。
另外:訪問的時候還有幾個前提條件
1.被引用的變量所在類必須被完整地定義,而不是只有前向聲明(例如只是一行class A;);
2.被引用的變量必須是引用處可以訪問的。
2.1.訪問變量的語句所在的類被聲明為被訪問的變量所在類的友元類;
2.2.訪問變量的語句所在的函數被聲明為被訪問變量所在類的友元函數;
2.3.被訪問變量被public修飾,且訪問變量的語句所在的類不是被訪問變量所在的類的private繼承派生類;
2.4.被訪問變量被protected修飾,且訪問變量的語句所在的類是被訪問變量所在的類的public繼承派生類;
2.5.訪問變量的語句所在的類定義在被訪問變量所在的類的內部。
現在假設滿足以上前提條件的A類的某個成員函數或成員初始化的語句要引用B類的成員m,
那么
1.當m是A類的靜態成員時,可以通過A::m引用;
2.當m是A類的非靜態成員,且對象a是類A的實例時,可以通過a.m引用。
以上基本包含了所有的情況。