1 #include <iostream> 2 using namespace std; 3 4 class A 5 { 6 public: 7 class B 8 { 9 public: 10 B(char* name){ 11 cout<<"constructing B:"<<name<<endl; 12 } 13 void printB(); 14 }; 15 B b; 16 A():b("In class A"){ //A的構造函數 17 cout<<"constructing A"<<endl; 18 } 19 }; 20 21 void A::B::printB(){ 22 cout<<"B's member function"<<endl; 23 } 24 25 int main(int argc,char* argv[]) 26 { 27 A a; 28 A::B b("outside of A"); 29 b.printB(); 30 }程序輸出結果:
1 constructing B:In class A 2 constructing A 3 constructing B:outside of A 4 B's member function對嵌套類的若干說明: (1)從作用域的角度來看,嵌套類與外圍類是兩個完全獨立的類,只是主從關系,二者不能相互訪問,也不存在友元關系。 (2)從訪問權限的角度來看,嵌套類既可為私有,也可為公有。在上面的例子中,嵌套類B的訪問權限是public,可以在外圍類的成員函數之外使用該嵌套類,使用時加上名字限定。如果將嵌套類B的訪問權限設置為private,那麼只能在外圍類內使用。 (3)嵌套類中的成員函數可以在它的類體外定義。 (4)嵌套類可以訪問外圍類的靜態成員變量,即使它的訪問權限是私有的,訪問方式通過”ClassName::staticVarName”來直接訪問。
1 #include<iostream> 2 using namespace std; 3 4 class A 5 { 6 public: 7 A(){ 8 cout << "A construct" <<endl; 9 } 10 class B{ 11 public: 12 B(){ 13 cout << "B construct" <<endl; 14 } 15 }; 16 }; 17 18 int main() 19 { 20 A ca; 21 cout<<"-------------"<<endl; 22 A::B b; 23 return 0; 24 }
程序輸出結果:
1 A construct 2 ------------- 3 B construct
可以看到,在進行創建一個外圍類的對象時,只執行外圍類的構造函數,而並不會先執行嵌套類的構造函數然後再執行外圍類的構造函數。嵌套類與繼承或成員對象是不同的。
【轉載】http://www.cnblogs.com/qzhforthelife/archive/2013/07/31/3226885.html
先上代碼:
1 class Outer 2 { 3 private: 4 int m_outerInt; 5 public: 6 Outer(){m_outerInt=0;} 7 8 //內部類定義開始 9 class Inner 10 { 11 public: 12 Inner(){m_innerInt=1;} 13 private: 14 int m_innerInt; 15 public: 16 void DisplayIn(){cout<<m_innerInt<<endl;} 17 } ; 18 //End內部類 19 void DisplayOut(){cout<<m_outerInt<<endl;} 20 }; 21 22 int main() 23 { 24 Outer out; 25 Outer::Inner in; 26 out.DisplayOut(); 27 in.DisplayIn(); 28 29 return 0; 30 }
如上面代碼所示,這種情況下,外部類與內部類其實聯系並不大,外部類無非僅僅限定了內部類類名的作用域范圍,完全可以加上Outer限定之後像使用任何其他類一樣來使用內部類,Outer於Inner而言僅僅是一種命名空間。
提問:上面代碼中,內部類(Inner)成員函數(比如DisplayIn)如何訪問外部類(Outer)數據成員呢?
答:問這個問題之前,先要明白一個事實:將來你是在一個Inner實例對象上調用Inner的成員函數的,而所謂的“訪問外部類數據成員”這種說法是不合理的,“外部類”及任何類,只是代碼而已,是一種說明,從內存的角度來講,程序運行起來之後,代碼存儲在代碼區,所以應該問“如何訪問外部類實例的數據成員”(數據成員針對的是每個對象而言的),如此,你得先有一個外部類實例(或者實例的指針),然後才能談訪問。
退一步講,如果你不管三七二十一,直接在Inner的DisplayIn方法裡加上這樣一行:
1 m_outerInt=10;
然後你編譯、鏈接也都通過了(事實上這是不可能的),那麼,在main函數中:
1 int main() 2 { 3 Outer::Inner in; 4 in.DisplayIn(); 5 6 return 0; 7 }
如果這樣你都能正常運行,天理何在?DisplayIn中的m_outerInt到底是哪個實例的數據?
所以,為了避免這樣荒唐的事情發生,語法層面就已經使得上述不可能發生:連編譯都不會通過。
提問:把上面代碼中的Inner設置為Outer的友元類之後,能解決問題嗎?
答:該提問者不僅犯了第一個提問者的錯誤,還誤解了友元的含義。
友元舉例:
1 class Inner; 2 3 class Outer 4 { 5 private: 6 int m_outerInt; 7 public: 8 Outer(){m_outerInt=0;} 9 void DisplayOut(){cout<<m_outerInt<<endl;} 10 friend Inner; 11 }; 12 13 class Inner 14 { 15 private: 16 int m_innerInt; 17 public: 18 Inner(){m_innerInt=1;} 19 void DisplayIn(){cout<<m_innerInt<<endl;} 20 //友元影響的函數 21 void TestFriend(Outer out) 22 { 23 cout<<"Good Friend:"<<out.m_outerInt<<endl; 24 } 25 } ; 26 27 int main() 28 { 29 Outer out; 30 out.DisplayOut(); 31 Inner in; 32 in.DisplayIn(); 33 in.TestFriend(out); 34 return 0; 35 }
經過以上說明後,類Inner的所有成員函數都是類Outer的友元函數,能存取類Outer的私有成員和保護成員。
聲明友元的目的是讓類的非成員函數或者類能訪問該類對象的私有和受保護成員,使用友元類時注意:(2) 友元關系是單向的,不具有交換性。若類B是類A的友元,類A不一定是類B的友元,要看在類中是否有相應的聲明。
(3) 友元關系不具有傳遞性。若類B是類A的友元,類C是B的友元,類C不一定是類A的友元,同樣要看類中是否有相應的申明
(4) 友元函數並不是類的成員函數,因此在類外定義的時候不能加上class::function name
(5) 友元函數不能直接訪問類中的私有成員只能通過類的對象來訪問 私有成員 ,
class A{int a; pulbic:friend void g();}
則void g(){a=2;}就是錯誤的
void g(){A m; m.a=2;}就是正確的
(6) friend 出現的位置對友元來說無關緊要。即把友元聲明在公有私有和受保護的位置都是一樣的。
內部類如果想達到友元訪問效果(直接通過實例或者實例指針來訪問實例的非公有成員),是不需要另外再聲明為friend的,原因不言自明:都已經是自己人了。
提問:內部類實例(作為外部類的數據成員)如何訪問外部類實例的成員呢?
見如下代碼:
1 #include <iostream> 2 #define METHOD_PROLOGUE(theClass, localClass) \ 3 theClass* pThis = ((theClass*)((char*)(this) - \ 4 offsetof(theClass, m_x##localClass))); \ 5 6 using namespace std; 7 8 class Outer 9 { 10 private: 11 int m_outerInt; 12 public: 13 Outer(){m_outerInt=0;} 14 //內部類定義開始 15 class Inner 16 { 17 private: 18 int m_innerInt; 19 public: 20 Inner(){m_innerInt=1;} 21 22 void DisplayIn(){cout<<m_innerInt<<endl;} 23 // 在此函數中訪問外部類實例數據 24 void setOut() 25 { 26 METHOD_PROLOGUE(Outer,Inner); 27 pThis->m_outerInt=10; 28 } 29 } m_xInner; 30 //End內部類 31 32 void DisplayOut(){cout<<m_outerInt<<endl;} 33 }; 34 35 int main() 36 { 37 Outer out; 38 out.DisplayOut(); 39 out.m_xInner.setOut(); 40 out.DisplayOut(); 41 return 0; 42 }
看main函數:程序執行完main函數第一句後,內存中便有了一個數據塊,它存儲著out的數據,而m_xInner也在數據塊中,當然,&out和this指針(外部類)都指向該內存塊的起始位置,而內部類代碼中的this指針當然就指向m_xInner的起始內存了,offsetof(theClass, m_x##localClass)獲得的便是m_xInner在該內存塊中與該內存塊起始地址(這正是out的地址)的距離(偏移),即內部類this-外部類this的差值(以字節為單位)這樣,用內部類this減去其自身的偏移,便可得到pThis。有了out的地址,基本上可以對其為所欲為了,至於為何要有char*強轉,可以go to definition of offsetof,可以看到其實現中有個關於char的轉換。