C++ 类访问控制public/private/protected探讨
原帖如下
1?#include?<IOSTREAM>
?2?using?namespace?std;
?3?
?4?class?A{
?5?public:
?6?????A(int?i_,int?j_)
?7?????{
?8?????????i=i_;
?9?????????j=j_;
10?????}
11?????void?disp(A?&a)
12?????{
13?????????cout<<a.i<<endl<<a.j<<endl;
14?????}
15?
16?private:
17?????int?i;
18?protected:
19?????int?j;
20?};
21?
22?int?main(int?argc,?char*?argv[])
23?{
24?????A?a(123,456);
25?????A?b(789,543);
26?????a.disp(b);
27?????b.disp(a);
28?
29?????return?0;
30?}
初看起來,倒是會產生疑問。為什么會這樣,是否有bug?
仔細考究起來,我們其實可以這樣看待類和對象:
類是將數據成員和進行于其上的一系列操作(成員函數)封裝在一起,注意:成員函數可以操作數據成員(可以稱類中的數據成員為泛數據成員)!
對象是類的實例化,怎樣理解實例化?其實每一個實例對象都只是對其中的數據成員初始化,內存映像中每個對象僅僅保留屬于自己的那份數據成員副本。而成員函數對于整個類而言卻是共享的,即一個類只保留一份成員函數。
那么每個對象怎樣和這些可以認為是“分離”的成員函數發生聯系,即成員函數如何操作對象的數據成員?記住this指針,無論對象通過(.)操作或者(->)操作調用成員函數,編譯時刻,編譯器都會將這種調用轉換成我們常見的全局函數的形式,并且多出一個參數(一般這個參數放在第一個),然后將this指針傳入這個參數。于是就完成了對象與成員函數的綁定(或聯系).
實例化后就得到同一個類的多個不同的對象,既然成員函數共享的,那么成員函數就可以操作對象的數據成員。
問題是現在有多個對象,成員函數需要知道操作的是哪個對象的數據成員?
比如有對象obj1和obj2,都屬于A類,A類有public成員函數foo()
如果obj1調用該函數,編譯時會給foo函數傳入this指針,obj1,foo中操作obj1自身的成員就不用任何修飾,直接訪問,因為其中的數據成員自動根據this指針找到。
如果obj1調用該函數,同樣可以訪問同類的其他對象的數據成員!那么你需要做的是讓foo函數知道是同類對象中哪個對象的數據成員,一個解決辦法是傳入同類其他對象的指針或引用,那么就可以操作同類其他對象的數據成員。
foo(A &obj)
這樣定義,然后調用:
obj1.foo(obj2)
就可以在obj1訪問obj2的數據成員,而無論這些數據成員是private還是protected
搬出C++ Object Model,可以畫出各個對象的內存map就可以更清晰的看出:
總結:C++的訪問修飾符的作用是以類為單位,而不是以對象為單位。
通俗的講,同類的對象間可以“互相訪問”對方的數據成員,只不過訪問途徑不是直接訪問.
步驟是:通過一個對象調用其public成員函數,此成員函數可以訪問到自己的或者同類其他對象的public/private/protected數據成員和成員函數(類的所有對象共用),而且還需要指明是哪個對象的數據成員(調用函數的對象自己的成員不用指明,因為有this指針;其他對象的數據成員可以通過引用或指針間接指明)
C++中public,protected,private訪問小結
第一:private,public,protected方法的訪問范圍.(public繼承下)
private: 只能由該類中的函數、其友元函數訪問,不能被任何其他訪問,該類的對象也不能訪問.
protected: 可以被該類中的函數、子類的函數、以及其友元函數訪問,但不能被該類的對象訪問
public: 可以被該類中的函數、子類的函數、其友元函數訪問,也可以由該類的對象訪問
注:友元函數包括兩種:設為友元的全局函數,設為友元類中的成員函數
第二:類的繼承后方法屬性變化:
使用private繼承,父類的所有方法在子類中變為private;
使用protected繼承,父類的protected和public方法在子類中變為protected,private方法不變;
使用public繼承,父類中的方法屬性不發生改變;?
?
| public: | protected: | private: | |
| public繼承 | public | protected | --- |
| protected繼承 | protected | protected | --- |
| private繼承 | private | private | --- |
protected繼承和private繼承能降低訪問權限
再次提到:可以提供訪問行為的主語為“函數”。
類體內的訪問沒有訪問限制一說,即private函數可以訪問public/protected/private成員函數或數據成員,同理,protected函數,public函數也可以任意訪問該類體中定義的成員
public繼承下,基類中的public和protected成員繼承為該子類的public和protected成員(成員函數或數據成員),然后訪問仍然按類內的無限制訪問
| 對于類域范圍內,成員函數訪問無所謂訪問限制。 ?2?using?namespace?std; ?3? ?4?class?C{ ?5?public: ?6?????C(int?val)?:?m_c(val)?{} ?7?private: ?8?????int?m_c; ?9?}; 10? 11?class?D:?public?C{ 12?public: 13?????D(int?val1,?int?val2)?:?C(val1),?m_d(val2)?{} 14?????int?m_d; 15?}; 16? 17?int?main() 18?{ 19? 20? 21?????cout?<<?sizeof(C)?<<?"?"?<<?sizeof(D)?<<?endl; //?4??8 22?????D?obj(2,?25); 23?????cout?<<?&obj?<<?"?"?<<?&obj.m_d?<<?endl; //0x0012FF78???0X0012FF7C 24?????//cout?<<?obj.m_c;? //error,?不能訪問 25? 26?????D?*ptr?=?&obj; 27?????int?*iptr?=?(int?*)ptr; 28?????cout?<<?*iptr?<<?"?"?<<?*(iptr+1)?<<?endl;//2??25 29????? 30?????return?0; 31?} 32? 33?
|
下面摘自博客園的一篇,相當精辟的理解:
?
下面這個問題摘自論壇的一個帖子:
已知3個類O、P和Q,類O中定義了一個私有方法F1、一個公有方法F2和一個受保護的方法F3:類P和類Q是類O的派生類,其繼承方式如下所示:
class P : protected O {…};
class Q : public O {…};
關于方法F1的描述中正確的是___(34)___;關于方法F2韻描述中正確的是___(35)___;關于方法F3的描述中正確的是___(36)___。
(34)
A.方法F1無法被訪問
B.只有在類O內才能訪問方法F1
C.只有在類P內才能訪問方法F1
D.只有在類Q內才能訪問方法F1
(35)
A.類O、P和Q的對象都可以訪問方法F2
B.類P和Q的對象都可以訪問方法F2
C.類0和Q的對象都可以訪問方法F2
?D.只有在類P內才能訪問方法F2
(36)A.類0、P和Q的對象都可以訪問方法F3
B.類0、P和Q的對象都不可以訪問方法F3
C.類0和Q的對象都可以訪問方法F3
D.類P和Q的對象都可以訪問方法F3。
有甚么辦法可以簡單地記住這許多的規則??下文告訴你一個根本不需要記的辦法。
顧名思義,private/public/protected 分別表示 私有/公開/保護,它們是一組用于訪問權限控制的關鍵字。那么首先,需要澄清的一個關鍵點是,是要控制誰訪問誰的權限?這個訪問的主語(施事)是誰?賓語(受事)是誰?
我們經常聽到這樣的說法:
1)一個類友元可以訪問該類的任何成員(包括成員變量及成員方法,下同)。
2)private成員只有該類自身可以訪問,protected成員只有該類及其派生類可以訪問,public成員所有的人都可以訪問。
賓語(受事)是誰這一點很明確,是類的成員(包括成員變量及成員方法)。主語(施事)是誰?這是讓大家發生混淆的關鍵點。也是這個說法中含糊不清的地方。
想清楚一點,其實主語(施事)指的是一個函數,而不是類(當然更不是變量)。private/public/protected要控制的是一個函數(施事)對一個類的成員(包括成員變量及成員方法)的訪問權限。因此比較完整的說法是:
1)一個類友元(包含友元函數或者友元類的所有成員函數)可以訪問該類的任何成員(包括成員變量及成員方法)。
2)除去友元外,private成員只有該類自身的成員函數可以訪問,protected成員只有該類的成員函數及其派生類的成員函數可以訪問,public成員則所有的函數都可以訪問。
也就是說,當我們說一個類可以訪問XXX,其實暗指這個類的成員函數可以訪問XXX。了解了這一點,外加一條顯而易見的規則,上面的問題就不難回答了。這條規則是:
3)派生類在繼承時可削弱成員的訪問權限(通過protected/private修飾)。例如上面的例子class P : protected O {…}; 那么某個函數通過類P訪問O中成員時,該函數對類O中的public成員只有protected權限。
補充:有一種技術叫Member Spy(類成員間諜),通過該技術派生類可將基類的protected成員修改為public權限。這種技術用到了using關鍵字。舉例如下:
class A
{
protected:
int m_data;
};
class?SpyA : public A
{
public:
using A::m_data;
};
void TestSpy(A* pA)
{
SpyA* pSpyA = static_cast<SpyA*>(pA);
// 強制轉換A為SpyA,這要求SpyA沒有成員變量且沒有重載A中的虛函數。
// 現在你可以通過pSpyA訪問m_data了。例如:int data = pSpyA->m_data;
}
由于這種技術用到了強制類型轉換,當謹慎使用。
題目:自己定義一個class,它只有一個數據成員,且為private, 其成員函數都為public, 它生成兩個對象obj1, obj2, 先要求用最少的成員函數實現obj1訪問obj2的private數據成員。
實現一:
?
?
?
總結
以上是生活随笔為你收集整理的C++ 类访问控制public/private/protected探讨的全部內容,希望文章能夠幫你解決所遇到的問題。