1. 程式人生 > >C++巢狀類的使用及對外部類的訪問許可權

C++巢狀類的使用及對外部類的訪問許可權

本人能力、精力有限,所言所感都基於自身的實踐和有限的閱讀、查閱,如有錯誤,歡迎拍磚,敬請賜教——部落格園:錢智慧。

先上程式碼:

複製程式碼
 1 class Outer
 2 {
 3 public:
 4     Outer(){m_outerInt=0;}
 5 private:
 6     int m_outerInt;
 7 public:
 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 public: 20 void DisplayOut(){cout<<m_outerInt<<endl;} 21 }; 22 23 int main() 24 { 25 Outer out; 26 Outer::Inner in; 27 out.DisplayOut(); 28 in.DisplayIn();
29 30 return 0; 31 }
複製程式碼

如上面程式碼所示,這種情況下,外部類與內部類其實聯絡並不大,外部類無非僅僅限定了內部類類名的作用域範圍,完全可以加上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 public:
 6     Outer(){m_outerInt=0;}
 7 private:
 8     int m_outerInt;
 9 public:
10     /*//內部類定義開始
11     class Inner
12     {
13     public:
14         Inner(){m_innerInt=1;}
15     private:
16         int m_innerInt;
17     public:
18         void DisplayIn(){cout<<m_innerInt<<endl;}
19     } ;
20     //End內部類*/
21 public:
22     void DisplayOut(){cout<<m_outerInt<<endl;}
23     friend Inner;
24 };
25 class Inner
26 {
27 public:
28     Inner(){m_innerInt=1;}
29 private:
30     int m_innerInt;
31 public:
32     void DisplayIn(){cout<<m_innerInt<<endl;}
33     //友元影響的函式
34     void TestFriend(Outer out)
35     {
36         cout<<"Good Friend:"<<out.m_outerInt<<endl;
37     }
38 } ;
39 
40 int main()
41 {
42     Outer out;
43     out.DisplayOut();
44     Inner in;
45     in.DisplayIn();
46     in.TestFriend(out);
47     return 0;
48 }
複製程式碼

內部類如果想達到友元訪問效果(直接通過例項或者例項指標來訪問例項的非公有成員),是不需要另外再宣告為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 public:
11     Outer(){m_outerInt=0;}
12 private:
13     int m_outerInt;
14 public:
15     //內部類定義開始
16     class Inner
17     {
18     public:
19         Inner(){m_innerInt=1;}
20     private:
21         int m_innerInt;
22     public:
23         void DisplayIn(){cout<<m_innerInt<<endl;}
24         // 在此函式中訪問外部類例項資料
25         void setOut()
26         {
27             METHOD_PROLOGUE(Outer,Inner);
28             pThis->m_outerInt=10;
29         }
30     } m_xInner;
31     //End內部類
32 public:
33     void DisplayOut(){cout<<m_outerInt<<endl;}
34 };
35 
36 int main()
37 {
38     Outer out;
39     out.DisplayOut();
40     out.m_xInner.setOut();
41     out.DisplayOut();
42     return 0;
43 }
複製程式碼

看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的轉換。

提問:巢狀類為什麼可以訪問外圍類的私有靜態函式而不可訪問非靜態函式?

因為巢狀類預設是外部類的友元類,所以可以訪問其私有成員,這其中就包含了外部類的靜態成員。而不可以訪問外部類的非靜態成員,這是因為訪問非靜態成員需要物件,在沒有外部類物件的前提下,是不能夠通過外部類物件來訪問其成員的。如果在內部類中持有外部類的物件,則可以通過該外部類物件訪問外部類中的非靜態成員。 http://www.cnblogs.com/RealOnlyme/archive/2012/06/14/2549156.html

  在一個類中定義的類稱為巢狀類,定義巢狀類的類稱為外圍類。

  定義巢狀類的目的在於隱藏類名,減少全域性的識別符號,從而限制使用者能否使用該類建立物件。這樣可以提高類的抽象能力,並且強調了兩個類(外圍類和巢狀類)之間的主從關係。下面是一個巢狀類的例子:   

class A  { public: class B    { public:      … private:      …    }; void f(); private:

相關推薦

C++與內部類

————————————————–先從定義上來區分————————————————– 巢狀類       所謂巢狀類就是可以在一個類中定義另一個類。這個被巢狀的類的作用域就只在它的上一級類中。       外圍類需要使用巢狀類物件作為底層實現,並且該巢狀類

C++的使用對外部類訪問許可權

本人能力、精力有限,所言所感都基於自身的實踐和有限的閱讀、查閱,如有錯誤,歡迎拍磚,敬請賜教——部落格園:錢智慧。 先上程式碼: 1 class Outer 2 { 3 public: 4 Outer(){m_outerInt=0;} 5 private:

C++中,呼叫外部類函式例子

class nestedClass // 內部類 { public: nestedClass() { testNestedClass(); } voi

C++ 與外圍以及區域性對成員變數的訪問 【資料結構】

參考資料:《資料結構c++語言描述》 概念: 在一個類中定義的為巢狀類,定義巢狀類的類稱為外圍類。巢狀類只能在外圍類中使用。 定義巢狀類的目的就是為了隱藏資訊,這樣可以提高類的抽象能力。 例子如下: 其中,類B是一個巢狀類,類A是外圍類,類B定義在類A的類體內。 若干說

C++在單例模式Singleton中自動釋放堆記憶體的應用

首先放出單例模式中的程式碼: singleton.h #ifndef SINGLETON_H #define SINGLETON_H #include <iostream> #include

Java中的、內部類、靜態內部類

在Java中我們在一個類的內部再定義一個類,如下所示:class OuterClass { ... class NestedClass { ... } }那麼在上面的例子中我們稱OuterClass為外圍類(enclosing clas

靜態和內部類的區別

一. 什麼是巢狀類及內部類?  可以在一個類的內部定義另一個類, 這種類稱為巢狀類(nested classes),它有兩種型別: 靜態巢狀類和非靜態巢狀類.靜態巢狀類使用很少, 最重要的是非靜態巢狀類, 也即是被稱作為內部類(inner).巢狀類從JDK1.1開始引入

深入理解JAVA的和內部類

巢狀類參看這篇文章 內部類詳細參看這篇文章 值得注意的是 靜態內部類不能訪問外部非靜態成員(受Java靜態成員不能訪問非靜態成員約定的約束) 內部類的.class檔名稱格式如下: 如果是靜態巢狀類、內部巢狀類,則表示為OuterClass$InnerClass.cla

Java例項說明 包括內部類(即非靜態)和靜態 兩者的區別

內部類例項程式碼: public class OuterMyTest {class InnerMyTest{}  public static void main(String[] args) {InnerMyTest innerMyTest = new InnerMyT

【Java學習筆記】靜態和內部類

public class Outer { int outer_x = 100;     class Inner{       public int y = 10;       private int z = 9;       int m = 5;       publ

介紹和內部類

在另一個類中定義的類就是巢狀類(nested classes)。巢狀類的範圍由裝入它的類的範圍限制。這樣,如果類B被定義在類A之內,那麼B為A所知,然而不被A的外面所知。巢狀類可以訪問巢狀它的類的成員,包括private 成員。但是,包圍類不能訪問巢狀類的成員。 巢狀類一般有

深入理解java和內部類、匿名

四、在外部類中定義內部類 匿名類就是沒有名字的內部類,是內部類的一種特殊情況。?????????  這句話對嗎??? 前端時間在寫.net專案中,一直錯將.cs裡的兩個class當作內部類,原來是一個檔案裡的兩個類而已,這讓我想起了Java中的內部類,比較內部類,那麼還有兩個類,那就是匿名類和匿名

Kotlin程式設計之,內部類,匿名內部類

Kotlin程式設計相關知識點介紹: 和Java程式設計類似,在Kotlin程式設計也有巢狀類和內部類,及匿名內部類。 開始編寫一個案例,來了解這三者,程式碼如下: package com

Java(內部類)總結

巢狀類(nested class)是指被定義在另一個類的內部的類。巢狀類的目的應該只是為它的外圍類(enclosing class)提供服務。如果巢狀類將來可能會用於其他某個環境中,它就應該是頂層類,而不是被設計為巢狀類。巢狀類分如下四種: 靜態成員類(static mem

Kotlin和內部類

巢狀類 類可以巢狀在其他類中,需要通過外部類才可以訪問巢狀類的成員,外部類.巢狀類.巢狀類成員。巢狀類不能直接訪問外部類的成員。 class Outer { private val bar: Int = 1 class Nested {

C++的使用方法

     在一個類的內部定義另一個類,我們稱之為巢狀類(nested class),或者巢狀型別。之所以引入這樣一個巢狀類,往往是因為外圍類需要使用巢狀類物件作為底層實現,並且該巢狀類只用於外圍類的實現,且同時可以對使用者隱藏該底層實現。    雖然巢狀類在外圍類內部定義

C++ 使用

C++巢狀類 1、巢狀類的名字只在外圍類可見。 2、類的私有成員只有類的成員和友元可以訪問,因此外圍類不可以訪問巢狀類的私有成員。巢狀類可以訪問外圍類的成員(通過物件、指標或者引用)。 3、一個好的巢狀類設計:巢狀類應該設成私有。巢狀類的成員和方法可以設為 public 。

java和內部類、匿名

4、匿名內部類 abstract class Person { public abstract void showCareer(); } public class Teacher extends Person{ @Override public void showCareer()

10、【C++】前向宣告、、區域性(內部類

一、前向宣告     在C++中,類需要先定義,而後才能被例項化,但是實際存在一種場景是:兩個類需要相互引用或相互成為類中的子物件成員時,就無法先定義使用,在編譯環節就出現錯誤導致編譯失敗,這時就需要用到前向宣告,此外,前向宣告的類不能被例項化。 【示例】 //

C++ nested class 與外圍 訪問問題

/* 巢狀類 nested class 巢狀類的引入是為了更好的名稱空間使用。 巢狀類是名字在其外圍類的作用域中可見,但在其他類作用域或定義外圍類的作用域中不可見。 巢狀類的名字將不會與另一作用域中宣告的名字衝突。 但巢狀類是獨立的類,基本上與他們的外圍類不相關,因此外