本人能力、精力有限,所言所感都基于自身的实践和有限的阅读、查阅,如有错误,欢迎拍砖,敬请赐教——博客园:钱智慧。

先上代码:

 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. Java通过继承外部类来建立该外部类的protected内部类的实例(转)

    原文链接:http://blog.sina.com.cn/s/blog_7de00ff60102xffx.html 如果想要在外部类的导出类(子类)中建立该外部类的为protected权限的内部类的实 ...

  3. C++之内部类(内部类就是外部类的友元类,单向友元。只是内部类比友元类多了一点权限)

    1. 内部类的概念 如果一个类定义在另一个类的内部,这个内部类就叫做内部类.注意此时这个内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去调用内部类.外部类对内部类没有任何优越的访问权限. ...

  4. Second Day: 关于Button监听事件的三种方法(匿名类、外部类、继承接口)

    第一种:通过匿名类实现对Button事件的监听 首先在XML文件中拖入一个Button按钮,并设好ID,其次在主文件.java中进行控件初始化(Private声明),随后通过SetOnClickLis ...

  5. C/C++基础----特殊工具和技术 (重载new和delete,RTT,限定作用域的枚举类型,类成员指针,嵌套类,局部类,volatile,链接指示 extern “C”)

    重载new和delete 1调用operator new( 或new[])标准库函数分配足够大的.原始的.未命名的内存空间以便存储特定类型的对象 2编译器运行相应地构造函数以构造这些对象,并为其传入初 ...

  6. 【C++ Primer | 19】嵌套类、局部类

    嵌套类 #include <iostream> using namespace std; class c1 { public: int a; void foo(); class c2 { ...

  7. 使用内部枚举类作为外部类的参数的Mybatis的参数该如何判断

    新写了一个接口,期望根据不同的参数来给数据库中不同的字段进行传值.这里使用了内部静态枚举类的方式进行传值,在写mybatis动态sql时,如果是普通对象,一般使用,那么使用枚举类,如何判断枚举类的值呢 ...

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

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

  9. 【转】C#类的分类(静态类、实例类、嵌套类、结构、简单的抽象类、简单的密封类)

    静态类 -------------------------------------------------------------------------------- 静态类就是在class关键字前 ...

  10. Java 嵌套类基础详解

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

随机推荐

  1. 配置 Struts2 Hello World

    http://javaweb.group.iteye.com/group/wiki/1505-struts2-under-helloworld---how-to-make-the-first-of-t ...

  2. yii2 model常用验证规则

    //字段必填[['username'],'required','message'=>'{attribute}不能为空!'][['username','password'], 'required' ...

  3. struct--file_operations

    struct--file_operations-----------------------------------------    struct file_operations是一个字符设备把驱动 ...

  4. const用法

    一.const作用 二.const用法 1.修饰一般常量   修饰符const可以用在类型说明符前,也可以用在类型说明符后. 例如: ; ; 2.修饰常数组  修饰符const可以用在类型说明符前,也 ...

  5. 【Error listenerStart】 Error listenerStart Context [] startup failed due to previous errors

    发给 报错信息 八月 12, 2015 11:58:19 上午 org.apache.coyote.AbstractProtocol start 信息: Starting ProtocolHandle ...

  6. Event Aggregator

    /** * Created with JetBrains WebStorm. * User: 宇乔 * Date: 13-8-2 * Time: 下午3:01 * To change this tem ...

  7. input标签文字点击变颜色

    <input type="text" class="ser_input"value="从这里搜索(^_^)" onfocus=&quo ...

  8. [cc150] 括号问题

    Implement an algorithm to print all valid ( properly opened and closed) combinations of n-pairs of p ...

  9. 1010 [HNOI2008]玩具装箱toy

    斜率优化dp: 推荐学习http://www.cnblogs.com/perseawe/archive/2012/05/12/bz1010.html 看着别人的题解自己学着推,终于理解了 #inclu ...

  10. table 表头固定

    <html> <head> <title>Test</title> <style type="text/css"> .d ...