用类去定义对象时,系统会为每一个对象分配存储空间。如果一个类包括了数据和函数,要分别为数据和函数的代码分配存储空间。按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的数据和函数代码分配存储单元,如下图所示。

能否只用一段空间来存放这个共同的函数代码段,在调用各对象的函数时,都去调用这个公用的函数代码。如下图所示。

显然,这样做会大大节约存储空间。C++编译系统正是这样做的,因此每个对象所占用的存储空间只是该对象的数据部分(虚函数指针和虚基类指针也属于数据部分)所占用的存储空间,而不包括函数代码所占用的存储空间。

看如下测试代码

class D
{
public:
void printA()
{
cout<<"printA"<<endl;
}
virtual void printB()
{
cout<<"printB"<<endl;
}
};
int main(void)
{
D *d=NULL;
d->printA();
d->printB();
}

问题:以上代码的输出结果是什么?

C++程序的内存格局通常分为四个区:全局数据区(data area),代码区(code area),栈区(stack area),堆区(heap area)(即自由存储区)。全局数据区存放全局变量,静态数据和常量;所有类成员函数和非成员函数代码存放在代码区;为运行函数而分配的局部变量、函数参数、返回数据、返回地址等存放在栈区;余下的空间都被称为堆区。根据这个解释,我们可以得知在类的定义时,类成员函数是被放在代码区,而类的静态成员变量在类定义时就已经在全局数据区分配了内存,因而它是属于类的。对于非静态成员变量,我们是在类的实例化过程中(构造对象)才在栈区或者堆区为其分配内存,是为每个对象生成一个拷贝,所以它是属于对象的。

应当说明,常说的“某某对象的成员函数”,是从逻辑的角度而言的,而成员函数的存储方式,是从物理的角度而言的,二者是不矛盾的。

下面我们再来讨论下类的静态成员函数和非静态成员函数的区别:静态成员函数和非静态成员函数都是在类的定义时放在内存的代码区的,因而可以说它们都是属于类的,但是类为什么只能直接调用静态类成员函数,而非静态类成员函数(即使函数没有参数)只有类对象才能调用呢?原因是类的非静态类成员函数其实都内含了一个指向类对象的指针型参数(即this指针),因而只有类对象才能调用(此时this指针有实值)。

回答开头的问题,答案是输出“printA”后,程序崩溃。类中包括成员变量和成员函数。new出来的只是成员变量,成员函数始终存在,所以如果成员函数未使用任何成员变量的话,不管是不是static的,都能正常工作。需要注意的是,虽然调用不同对象的成员函数时都是执行同一段函数代码,但是执行结果一般是不相同的。不同的对象使用的是同一个函数代码段,它怎么能够分别对不同对象中的数据进行操作呢?原来C++为此专门设立了一个名为this的指针,用来指向不同的对象。

需要说明,不论成员函数在类内定义还是在类外定义,成员函数的代码段都用同一种方式存储。不要将成员函数的这种存储方式和inline(内联)函数的概念混淆。不要误以为用inline声明(或默认为inline)的成员函数,其代码段占用对象的存储空间,而不用inline声明的成员函数,其代码段不占用对象的存储空间。不论是否用inline声明(或默认为inline),成员函数的代码段都不占用对象的存储空间。用inline声明的作用是在调用该函数时,将函数的代码段复制插人到函数调用点,而若不用inline声明,在调用该函数时,流程转去函数代码段的入口地址,在执行完该函数代码段后,流程返回函数调用点。inline与成员函数是否占用对象的存储空间无关,它们不属于同一个问題,不应搞混。

C++成员函数在内存中的存储方式的更多相关文章

  1. QList介绍(QList比QVector更快,这是由它们在内存中的存储方式决定的。QStringList是在QList的基础上针对字符串提供额外的函数。at()操作比操作符[]更快,因为它不需要深度复制)非常实用

    FROM:http://apps.hi.baidu.com/share/detail/33517814 今天做项目时,需要用到QList来存储一组点.为此,我对QList类的说明进行了如下翻译. QL ...

  2. <转载>浅谈C/C++的浮点数在内存中的存储方式

    C/C++浮点数在内存中的存储方式 任何数据在内存中都是以二进制的形式存储的,例如一个short型数据1156,其二进制表示形式为00000100 10000100.则在Intel CPU架构的系统中 ...

  3. C语言中浮点数在内存中的存储方式

    关于多字节数据类型在内存中的存储问题 //////////////////////////////////////////////////////////////// int ,short 各自是4. ...

  4. Float在内存中的存储方式及IEC61131处理

    Float在内存中的存储方式及IEC61131处理 1,fp32(32bits float)类型数据在存储器中占用4Bytes存储,且遵循IEEE-754标准: 一个浮点数分三部分组成: 符号位s(1 ...

  5. 数据在内存中的存储方式( Big Endian和Little Endian的区别 )(x86系列则采用little endian方式存储数据)

    https://www.cnblogs.com/renyuan/archive/2013/05/26/3099766.html 1.故事的起源 “endian”这个词出自<格列佛游记>.小 ...

  6. 实验:使用GDB查看结构体在内存中的存储方式

    结构体在内存中的表示形式是怎么样的? 结构体在内存中和普通变量存储没有太大的区别. 首先我们看看,计算机如何读取普通变量:   普通变量例如int是占据4个字节,计算机读内存的时候会从起始地址开始读, ...

  7. C/C++浮点数在内存中的存储方式

    一.内存表示 任何数据在内存中都是以二进制的形式存储的,浮点数的表示是把一个数的有效数字和数的范围在计算机的一个存储单元中分别予以表示,数的小数点位置随比例因子的不同而在一定范围内自由浮动.如下图是3 ...

  8. float和double在内存中的存储方式

    本文转载于:http://wenku.baidu.com/link?url=ARfMiXVHCwCZJcqfA1gfeVkMOj9RkLlR9fIexbgs9gDdV8rIS48A1_xe1y6YgX ...

  9. C/C++数据在内存中的存储方式

    目录 1 内存地址 2 内存空间   在学习C/C++编程语言时,免不了和内存打交道,在计算机中,我们存储有电影,文档,音乐等数据,这些数据在内存中是以什么形式存储的呢?下面做一下简单介绍. 本文是学 ...

随机推荐

  1. C#高低位分解转换备忘

    private void Form1_Load(object sender, EventArgs e) { , , , , , ); var arr = long2LowHight(time.ToFi ...

  2. spring redis 注解实现缓存机制

    1.xml配置 <bean id="poolConfigTax" class="redis.clients.jedis.JedisPoolConfig"& ...

  3. PythonStudy——文件操作习题 Document operation exercises

    # 1.统计文件数据中字母e出现的次数(不区分大小写)# 文件内容:hello friend, can you speak English!# 结果:4# 分析:将文件内容读出,然后统计读出的字符串中 ...

  4. jmeter 关联

    (1)正则表达式提取器 注:正则表达式部分配置说明 案例: 动态值:name=userSession value=119828.306682868zVzDzzipfcfDzQicpAVVVf> ...

  5. SSH原理及操作

    1:公钥与私钥(public and private key) 公钥:提供给远程主机进行数据加密的行为 私钥:远程主机收到客户端使用公钥加密数据后,在本地端使用私钥来解密 2:公钥与私钥进行数据传输时 ...

  6. 随机数的组合问题(JavaScript描述)

    随机数的组合问题在面试时是经常考的,比如之前我就被问到:“有一个可以生成1-5的随机数函数,怎样把它扩大到1-7?” 在解决这个问题之前,先来看看另外一个比较简单的问题:“有一个可以生成1-7的函数, ...

  7. Day 08 文件操作模式,文件复制,游标

    with open:将文件的释放交给with管理 with open('文件', '模式', encoding='utf-8') as f:    # 操作    pass​ a模式:追加写入 # t ...

  8. git项目提交后执行添加忽略操作

    需要删除文件暂存区中的忽略文件 git rm -r --cached 需要忽略的已提交文件或文件夹 eg: git rm -r --cached target/

  9. bzoj5048: 塌陷的牧场

    Description 农夫小Q将他的奶牛们饲养在一个长n宽m的矩形网格牧场中.行从上到下依次编号为1到n,列从左往右依次编号为1 到m.为了防止奶牛们逃跑,小Q在牧场外圈安装了一排电网,只要奶牛走出 ...

  10. solr6.4.1 搜索引擎(1)启动eclipse启动

    solr是一个java写的搜索引擎,所以支持java方式的eclipse调试. 本篇文章使用solr版本为6.4.1 一. 环境 solr 下载地址 http://archive.apache.org ...