先上代码:
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<
} ;
//End内部类
public:
void DisplayOut(){cout<
};
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<
} ;
//End内部类*/
public:
void DisplayOut(){cout<
friend Inner;
};
class Inner
{
public:
Inner(){m_innerInt=;}
private:
int m_innerInt;
public:
void DisplayIn(){cout<
//友元影响的函数
void TestFriend(Outer out)
{
cout<
}
} ;
int main()
{
Outer out;
out.DisplayOut();
Inner in;
in.DisplayIn();
in.TestFriend(out);
return ;
}
内部类如果想达到友元访问效果(直接通过实例或者实例指针来访问实例的非公有成员),是不需要另外再声明为friend的,原因不言自明:都已经是自己人了。
提问:内部类实例(作为外部类的数据成员)如何访问外部类实例的成员呢?
见如下代码:
#include
#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<
// 在此函数中访问外部类实例数据
void setOut()
{
METHOD_PROLOGUE(Outer,Inner);
pThis->m_outerInt=;
}
} m_xInner;
//End内部类
public:
void DisplayOut(){cout<
};
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++】嵌套类、友元
黄邦勇帅 里面关于嵌套类的介绍我有疑惑.里面11.9说在创建一个外围类的对象时先执行嵌套类的构造函数然后再执行外围类的构造函数,析构函数则以相反的方式执行. 可是我编程实验了一下,创建外围类对象时并不 ...
C++嵌套类(内部类与外部类)
在一个类中定义的类被称为嵌套类,定义嵌套类的类被称为外部类.; //不能访问 mytest::i = 10;//不能访问 } private: class mytest { int i; int j; ...
C++中内部类访问外部类的私有成员
首先,如果不知道什么是内部类InnerClass的话,就没必要往下看了. 尝试在C++中模仿apple objective-c 的Grand Dispatch简化多线程编程时,使用了boost::fu ...
139、Java内部类之使用this访问外部类属性
01.代码如下: package TIANPAN; class Outer { // 外部类 private String msg = "Hello World !"; class ...
JAVA 嵌套类和内部类
一.什么是嵌套类及内部类? 可以在一个类的内部定义另一个类,这种类称为嵌套类(nested classes),它有两种类型: 静态嵌套类和非静态嵌套类.静态嵌套类使用很少,最重要的是非静态嵌套类, ...
分析java 嵌套类与内部类
一.什么是嵌套类及内部类? 可以在一个类的内部定义另一个类,这种类称为嵌套类(nested classes),它有两种类型:静态嵌套类和非静态嵌套类.静态嵌套类使用很少,最重要的是非静态嵌套类 ...
Java 嵌套类基础详解
目录 1. 什么是嵌套类? 2. 为什么要使用嵌套类? 3. 嵌套类的类型 4. 静态嵌套类 5. 非静态嵌套类 5.1 成员内部类 5.2 局部内部类 5.3 匿名内部类 6. 嵌套接口 1. 什么 ...
Java基础 -- 嵌套类(非静态嵌套类、静态嵌套类)
可以将一个类的定义放在另一个类的内部定义,这样的类就被称为嵌套类,包含嵌套类的类被称为外部类(outer class),也可以叫做封闭类. 嵌套类可以分为两种: 静态嵌套类(Static Nested ...
随机推荐
Git Bash的一些命令和配置
查看git版本号: git --version 如果是第一次使用Git,你需要设置署名和邮箱: $ git config --global user.name "用户名" $ gi ...
解读Unity中的CG编写Shader系列六(漫反射)
转自 http://www.itnose.net/detail/6116553.html 如果前面几个系列文章的内容过于冗长缺乏趣味着实见谅,由于时间原因前面的混合部分还没有写完,等以后再补充,现在开 ...
微信小程序之动态获取元素宽高
我以前一直以为微信小程序不能动态获取view元素的宽高.但是自从看到: wx.createSelectorQuery() 这个api接口,以前的某些问题就能得到解决了... 那么,这个api接口怎么用 ...
C#基础加强(6)之引用相等与运算符重载
引用相等 介绍 在 C# 中可以通过 object.ReferenceEquals(obj1, obj2) 方法来判断两个变量引用的是不是同一个地址,如果是,那么就是引用相等. 引用相等是针对引用类型 ...
使用 lsyncd 同步文件
https://unix.stackexchange.com/questions/307046/real-time-file-synchronization https://github.com/ax ...
MeEclipse搭建SSH框架之———大体框架
必备:MyEclipse软件,SSH需要的jar包,数据库,连接数据库的驱动jar包 先搭建大体框架,再加别的东西,要不都不知道哪里错了 一.新建web项目 MyEclipse左边右键--->N ...
Loadrunner&#160;脚本开发-从文件读取数据并参数化
脚本开发-从文件读取数据并参数化 by:授客 QQ:1033553122 直接上代码: char* testfn() { int count, total = 0; //char buffer[1 ...
【知识碎片】getResource和getResourceAsStream
1. 前言 在Java中获取资源的时候,经常用到getResource和getResourceAsStream,本文总结一下这两种获取资源文件的路径差异. 2.Class.getResource(St ...
pyqt5 点开小窗口
# -*- coding: utf-8 -*- import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * class Fi ...
Linux巩固记录(8) Hbase shell 基本使用
继续前几篇内容,讲解hbase基本使用 1.进入hbase shell: hbase有很多种操作方式,比如shell,java客户端,webUI等,可以直接输入hbase进行提示 [root@mast ...