转载于:http://www.cnblogs.com/qzhforthelife/p/3226885.html

先上代码:

class Outer
{
public:
Outer(){m_outerInt=;}
private:
int m_outerInt;
public:
//内部类定义开始
class Inner
{
public:
Inner(){m_innerInt=;}
private:
int m_innerInt;
public:
void DisplayIn(){cout<<m_innerInt<<endl;}
} ;
//End内部类
public:
void DisplayOut(){cout<<m_outerInt<<endl;}
}; int main()
{
Outer out;
Outer::Inner in;
out.DisplayOut();
in.DisplayIn(); return ;
}

如上面代码所示,这种情况下,外部类与内部类其实联系并不大,外部类无非仅仅限定了内部类类名的作用域范围,完全可以加上Outer限定之后像使用任何其他类一样来使用内部类,Outer于Inner而言仅仅是一种命名空间。

提问:上面代码中,内部类(Inner)成员函数(比如DisplayIn)如何访问外部类(Outer)数据成员呢?

答:问这个问题之前,先要明白一个事实:将来你是在一个Inner实例对象上调用Inner的成员函数的,而所谓的“访问外部类数据成员”这种说法是不合理的,“外部类”及任何类,只是代码而已,是一种说明,从内存的角度来讲,程序运行起来之后,代码存储在代码区,所以应该问“如何访问外部类实例的数据成员”,如此,你得先有一个外部类实例(或者实例的指针),然后才能谈访问。

退一步讲,如果你不管三七二十一,直接在Inner的DisplayIn方法里加上这样一行:

 m_outerInt=;

然后你编译、链接也都通过了(事实上这是不可能的),那么,在main函数中:

int main()
{
Outer::Inner in;
in.DisplayIn(); return ;
}

如果这样你都能正常运行,天理何在?DisplayIn中的m_outerInt到底是哪个实例的数据?

所以,为了避免这样荒唐的事情发生,语法层面就已经使得上述不可能发生:连编译都不会通过。

提问:把上面代码中的Inner设置为Outer的友元类之后,能解决问题吗?


答:该提问者都不仅犯了第一个提问者的错误,还误解了友元的含义。

友元举例:

class Inner;

class Outer
{
public:
Outer(){m_outerInt=;}
private:
int m_outerInt;
public:
/*//内部类定义开始
class Inner
{
public:
Inner(){m_innerInt=1;}
private:
int m_innerInt;
public:
void DisplayIn(){cout<<m_innerInt<<endl;}
} ;
//End内部类*/
public:
void DisplayOut(){cout<<m_outerInt<<endl;}
friend Inner;
};
class Inner
{
public:
Inner(){m_innerInt=;}
private:
int m_innerInt;
public:
void DisplayIn(){cout<<m_innerInt<<endl;}
//友元影响的函数
void TestFriend(Outer out)
{
cout<<"Good Friend:"<<out.m_outerInt<<endl;
}
} ; int main()
{
Outer out;
out.DisplayOut();
Inner in;
in.DisplayIn();
in.TestFriend(out);
return ;
}

内部类如果想达到友元访问效果(直接通过实例或者实例指针来访问实例的非公有成员),是不需要另外再声明为friend的,原因不言自明:都已经是自己人了。

提问:内部类实例(作为外部类的数据成员)如何访问外部类实例的成员呢?

见如下代码:

#include <iostream>
#define METHOD_PROLOGUE(theClass, localClass) \
theClass* pThis = ((theClass*)((char*)(this) - \
offsetof(theClass, m_x##localClass))); \ using namespace std; class Outer
{
public:
Outer(){m_outerInt=;}
private:
int m_outerInt;
public:
//内部类定义开始
class Inner
{
public:
Inner(){m_innerInt=;}
private:
int m_innerInt;
public:
void DisplayIn(){cout<<m_innerInt<<endl;}
// 在此函数中访问外部类实例数据
void setOut()
{
METHOD_PROLOGUE(Outer,Inner);
pThis->m_outerInt=;
}
} m_xInner;
//End内部类
public:
void DisplayOut(){cout<<m_outerInt<<endl;}
}; int main()
{
Outer out;
out.DisplayOut();
out.m_xInner.setOut();
out.DisplayOut();
return ;
}

看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的转换。

C++之内部类与外部类(嵌套类)及友元的更多相关文章

  1. C#外部类、内部类(嵌套类)之间的成员访问特点

    最近程序中需要用到多线程工作下的单例模式.而其多种实现方法中,利用内部类实现懒汉模式是一种值得推荐的方式.顺便也就对内部类和外部类之间的关系做了一下研究,总结如下(理解不困难,不粘贴代码了,有需要的留 ...

  2. 【C++】嵌套类、友元

    黄邦勇帅 里面关于嵌套类的介绍我有疑惑.里面11.9说在创建一个外围类的对象时先执行嵌套类的构造函数然后再执行外围类的构造函数,析构函数则以相反的方式执行. 可是我编程实验了一下,创建外围类对象时并不 ...

  3. C++嵌套类(内部类与外部类)

    在一个类中定义的类被称为嵌套类,定义嵌套类的类被称为外部类.; //不能访问 mytest::i = 10;//不能访问 } private: class mytest { int i; int j; ...

  4. C++中内部类访问外部类的私有成员

    首先,如果不知道什么是内部类InnerClass的话,就没必要往下看了. 尝试在C++中模仿apple objective-c 的Grand Dispatch简化多线程编程时,使用了boost::fu ...

  5. 139、Java内部类之使用this访问外部类属性

    01.代码如下: package TIANPAN; class Outer { // 外部类 private String msg = "Hello World !"; class ...

  6. JAVA 嵌套类和内部类

    一.什么是嵌套类及内部类?  可以在一个类的内部定义另一个类,这种类称为嵌套类(nested classes),它有两种类型:  静态嵌套类和非静态嵌套类.静态嵌套类使用很少,最重要的是非静态嵌套类, ...

  7. 分析java 嵌套类与内部类

    一.什么是嵌套类及内部类?     可以在一个类的内部定义另一个类,这种类称为嵌套类(nested classes),它有两种类型:静态嵌套类和非静态嵌套类.静态嵌套类使用很少,最重要的是非静态嵌套类 ...

  8. Java 嵌套类基础详解

    目录 1. 什么是嵌套类? 2. 为什么要使用嵌套类? 3. 嵌套类的类型 4. 静态嵌套类 5. 非静态嵌套类 5.1 成员内部类 5.2 局部内部类 5.3 匿名内部类 6. 嵌套接口 1. 什么 ...

  9. Java基础 -- 嵌套类(非静态嵌套类、静态嵌套类)

    可以将一个类的定义放在另一个类的内部定义,这样的类就被称为嵌套类,包含嵌套类的类被称为外部类(outer class),也可以叫做封闭类. 嵌套类可以分为两种: 静态嵌套类(Static Nested ...

随机推荐

  1. 【movable-area、movable-view】 可移动区域组件说明

    movable-area.movable-view 可移动区域组件 原型: <movable-area scale-area="[Boolean]"> <mova ...

  2. CodeForces - 776C(前缀和+思维)

    链接:CodeForces - 776C 题意:给出数组 a[n] ,问有多少个区间和等于 k^x(x >= 0). 题解:求前缀和,标记每个和的个数.对每一个数都遍历到1e5,记录到答案. # ...

  3. HTML 之 表单

    关于HTML的表单 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset=&q ...

  4. 您的下个中文网站可以使用的5个高质量中文Webfont

    你有没有考虑为什么中文网站的版式风格不像大多数现代英文网站那样丰富?您想了解如何让您的下一个中文网站项目更吸引用户的眼球么?继续往下读吧…… 根据Smashing Magazine进行的一项调查显示  ...

  5. maven项目中没有resource文件夹的问题

    之前使用eclipse创建maven项目,文件夹都是建好的,这几次创建,都没有resource文件夹,需要手动创建resource. 现象描述 在eclipse中,创建maven项目有两种方式: 一种 ...

  6. leetcode个人题解——#17 Letter Combinations of a Phone Number

    思路:用深搜遍历九宫格字符串,一开始做的时候发生了引用指向空地址的问题,后来发现是vector不能直接=赋值. class Solution { public: int len; ]={"a ...

  7. 【SSH进阶之路】Struts + Spring + Hibernate 进阶开端(一)

    [SSH进阶之路]Struts + Spring + Hibernate 进阶开端(一) 标签: hibernatespringstrutsssh开源框架 2014-08-29 07:56 9229人 ...

  8. struts2之form标签theme属性详解

    struts2中theme属性包括xhtml,html,simple,ajax .默认是xhtml theme:设置struts2标签的主题,默认为xhtml. theme=xhtml时:会默认额外生 ...

  9. python函数中的位置参数、默认参数、关键字参数、可变参数区别

    一.位置参数 调用函数时根据函数定义的参数位置来传递参数. #!/usr/bin/env python # coding=utf-8 def print_hello(name, sex): sex_d ...

  10. Python练习—文件

    1.随机生成20个两位正整数,将其升序排序后再写入文本文件data_asc.txt中! import random alist = [random.randint(10,100) for i in r ...