C++之内部类(嵌套类)与外部类及友元
本人能力、精力有限,所言所感都基于自身的实践和有限的阅读、查阅,如有错误,欢迎拍砖,敬请赐教——博客园:钱智慧。
先上代码:
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++之内部类(嵌套类)与外部类及友元的更多相关文章
- c++中嵌套类,外部类访问内部类的私有成员变量
在嵌套类中,内部类可以直接访问外部类的私有成员变量,但是外部类不能直接访问内部类的私有成员变量,必须把外部类声明为内部类的友元类 /********************************** ...
- Java通过继承外部类来建立该外部类的protected内部类的实例(转)
原文链接:http://blog.sina.com.cn/s/blog_7de00ff60102xffx.html 如果想要在外部类的导出类(子类)中建立该外部类的为protected权限的内部类的实 ...
- C++之内部类(内部类就是外部类的友元类,单向友元。只是内部类比友元类多了一点权限)
1. 内部类的概念 如果一个类定义在另一个类的内部,这个内部类就叫做内部类.注意此时这个内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去调用内部类.外部类对内部类没有任何优越的访问权限. ...
- Second Day: 关于Button监听事件的三种方法(匿名类、外部类、继承接口)
第一种:通过匿名类实现对Button事件的监听 首先在XML文件中拖入一个Button按钮,并设好ID,其次在主文件.java中进行控件初始化(Private声明),随后通过SetOnClickLis ...
- C/C++基础----特殊工具和技术 (重载new和delete,RTT,限定作用域的枚举类型,类成员指针,嵌套类,局部类,volatile,链接指示 extern “C”)
重载new和delete 1调用operator new( 或new[])标准库函数分配足够大的.原始的.未命名的内存空间以便存储特定类型的对象 2编译器运行相应地构造函数以构造这些对象,并为其传入初 ...
- 【C++ Primer | 19】嵌套类、局部类
嵌套类 #include <iostream> using namespace std; class c1 { public: int a; void foo(); class c2 { ...
- 使用内部枚举类作为外部类的参数的Mybatis的参数该如何判断
新写了一个接口,期望根据不同的参数来给数据库中不同的字段进行传值.这里使用了内部静态枚举类的方式进行传值,在写mybatis动态sql时,如果是普通对象,一般使用,那么使用枚举类,如何判断枚举类的值呢 ...
- C++嵌套类(内部类与外部类)
在一个类中定义的类被称为嵌套类,定义嵌套类的类被称为外部类.; //不能访问 mytest::i = 10;//不能访问 } private: class mytest { int i; int j; ...
- 【转】C#类的分类(静态类、实例类、嵌套类、结构、简单的抽象类、简单的密封类)
静态类 -------------------------------------------------------------------------------- 静态类就是在class关键字前 ...
- Java 嵌套类基础详解
目录 1. 什么是嵌套类? 2. 为什么要使用嵌套类? 3. 嵌套类的类型 4. 静态嵌套类 5. 非静态嵌套类 5.1 成员内部类 5.2 局部内部类 5.3 匿名内部类 6. 嵌套接口 1. 什么 ...
随机推荐
- iOS之多线程浅谈
1)并发和并行的区别 在软件开发中不可避免的会遇到多线程的问题,在iOS客户端开发(或者.NET的winform或者wpf这样的cs程序)中就更不可避免的会用到多线程,在bs类型的web项目中要考虑一 ...
- hihocode 第九十二周 数论一·Miller-Rabin质数测试
题目链接 检测n是否为素数,数据范围为2 <= n <= 10^18; 思路:Miller_Rabin素数检测模板题,原理:在Fetmat定理的基础之上,再利用二次探测定理: 对于任意的正 ...
- MVC-列表页操作按钮调用脚本
如上图所示功能:点击右边的“编辑”和“重置按钮”,调用js实现弹出框功能. 1.写脚本: <script type="text/javascript"> functio ...
- online web design tool
https://webflow.com/ http://css-tricks.com/snippets/ https://www.fluidui.com/demos
- Javascript 5种方法实现过滤删除前后所有空格
第一种:循环检查替换 //供使用者调用 function trim(s){ return trimRight(trimLeft(s)); } //去掉左边的空白 function trimLeft(s ...
- 异常: http://www.ly.com/news/visa.html: java.io.IOException: unzipBestEffort returned null
nutch 运行时异常: http://www.ly.com/news/visa.html: java.io.IOException: unzipBestEffort returned null 参考 ...
- C#.NET连接mysql方法
C#访问MySQL数据库的方法 (1)首先需要下载C#访问MySQL数据库的ADO.NET驱动程序 下载地址为: http://dev.mysql.com/downloads/connector/ne ...
- BZOJ 3901 棋盘游戏 解题报告
这题有个重要性质: 我们设 Flag[i][j] 表示 (i, j) 是否被奇数个操作所覆盖, 也就是操作次数对 2 取模. 设 x = (n + 1) / 2. 那么对于所有的合法的操作方案, 令 ...
- codeforces 390D Inna and Sweet Matrix
几个小结论: 1.路径长度=i+j-1; 2.最简单的走法是先横走再竖着走或者先竖着走再横着走 #include<cstdio> #include<cstring> using ...
- Oracle----Key Word
desc|describe table_name DCL----column ----add -- add one column alter table product ); -- add multi ...