c++类内存大小

首先讨论下c,c没有类的概念,c写的程序是有main()开启的,然后各种函数的使用,这个main其实不是必须的,只是编译器需要一个入口,如果感兴趣可以搜索下,即使没有main,指定了其他函数入口依然可以。然后说c的函数,它由函数名调用,在我记录的c++Primer类别里,多次说函数名是这个函数的对象或者说地址,不知道是否正确,仅个人看法,当我们调用函数的时候,编译器把函数名替换成函数地址,然后运行程序的时候,call地址来运行函数,然后是堆栈上的操作。现在来说c++,c++用类来封装数据,包括成员变量和成员函数,于是乎一个函数被指定了是谁的成员函数,不是谁的成员函数,在写代码的时候,代码提醒功能就能标识出来是不是这个类的,,这里就需要提醒了,类成员函数和c里的函数一样都是全局的,只不过多了和隐含的this指针,他们都存放在代码段之中,都是函数名代表函数入口地址,那么就可能疑惑了,那到底编译器怎么判断这个函数到底是哪个类的啊,以至于代码提醒功能怎么提醒。。。对于这些问题,稍后再说。

以下内容是从网上找好多文章,然后顺势写的,感谢网上的各个文章,具体链接我就忘了,太多了。

记得有这两篇:

http://hi.baidu.com/lovestartian/item/5e10f99e1b1faedb1e4271a3
http://www.blue1000.com/bkhtml/c151/2010-11/69613.htm

类的普通成员、静态成员函数是不占类内存的,至于你说的函数指针在你的类中有虚函数的时候存在一个虚函数表指针,也就是说如果你的类里有虚函数则 sizeof(CObject)的值会增加4个字节。其实类的成员函数 实际上与 普通的全局函数一样。只不过编译器在编译的时候,会在成员函数上加一个参数,传入这个对象的指针。成员函数地址是全局已知的,对象的内存空间里根本无须保存成员函数地址。对成员函数(非虚函数)的调用在编译时就确定了。

像 myObject.Fun() 这样的调用会被编译成形如 _CObject_Fun( &myObject ) 的样子。调用的时候,像普通c函数一样,call这个函数的地址完成调用。所以说哪怕是类的私有成员函数,一样是一个全局的,只要知道了这个函数的地址,就可以调用它,那种对象名.方法名的调用方式,只是让你看起来类完成了数据与操作的封装性。访问类的私有数据,可以根据对象首地址,计算偏移来得到所有成员数据地址;私有成员函数并不和类对象地址有关,所以在访问私有函数的时候,就得像办法得到地址了,另外还需要传一个本类的实例进去。另外,在使用类函数指针的时候,我们还是通过对象名调用的,额,此处不想了,兴趣来了,可以深究下。于是我们说的类的成员函数,访问权限符等等规则只是编译层面上的概念,代码是就是操作内存里的数,没有什么规则可言,得到内存地址就能改数据。
函数是不算到sizeof中的,因为函数是代码,被各个对象共用,跟数据处理方式不同。对象中不必有函数指针,因为对象没必要知道它的各个函数的地址(调 用函数的是其他代码而不是该对象)。
类的属性是指类的数据成员,他们是实例化一个对象时就为数据成员分配内存了,而且每个对象的数据成员是对立的,而成员函数是共有的。
静态成员函数与一般成员函数的唯一区别就是没有this指针,因此不能访问非静态数据成员,并不是说静态成员函数是全局函数,成员函数就不是全局函数,总之,程序中的所有函数都是位于代码区的。
静态成员并不属于某个对象,sizeof取的是对象大小。
类分为成员变量和成员函数,我们先来讨论成员变量。 一个类对象的地址就是类所包含的这一片内存空间的首地址,这个首地址也就对应具体某一个成员变量的地址。类的内存大小和其唯一的成员变量的内存大小是一致的。内存地址也是一致的。他们甚至可以相互转换。就比如class A{ private: int i; };那么我可以A a; int t = *(int*)(&a);来得到i。另外多个私有变量,依然可以通过计算地址偏移来得到,不过要注意内存对齐这个概念,内存对齐是为了更好的寻址,额,具体可以搜索下。
所有的函数都是存放在代码区的,不管是全局函数,还是成员函数。
如果类含有虚函数,那么类里面将含有一个虚指针vptr,指向该类的虚表vtbl,一个指针占用四字节的地址,所以会在数据之外多4个字节。

OK,以上的内容很凌乱,不过是不是有那么点明白。。呵呵,,回到最上面的那个问题,,我现在为了让自己不一致纠结于这个问题而这么想,c函数/c++成员函数,他们都是代码段上的一块数据,在c++中编译器为了编译时能确定此函数是否为该类所拥有,于是编译器为该类维护了一个函数表,这个并不存在,编译完成之后就没有了,这样我就又能解决代码提醒功能和成员函数是全局的这种纠结,反正具体不清楚,,回头再慢慢学习,反正对于编译时确定的函数,在编译时函数名都被替换成了函数入口地址,而虚函数这些在运行时才确定的函数,因此需要一个虚函数表去确定要调用哪个函数。另外对于继承这个概念,子类从父类那里继承全部的东西,如果发生函数重载,那么依然有继承一份,自己重新有一份,虚函数也是这样,虽然他们是在虚表里维护,哎,不去纠结这些了,,从最开始学c++就接受了永远学不懂的事实,,不过其他语言封装的更严谨,编译上就没那么多纠结之处了,底层还是一样,所以是不是可以说,现在纠结的都是编译的问题。。。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值