探究c++对象模型之data语义学(一)
来源:互联网 发布:windows显示后缀名 编辑:程序博客网 时间:2024/06/16 12:22
c++标准中有这样一个规定:
"no object shall have thesame address in memory as any other variable".
由此规定,导致几乎所有的编译器对一个空类都会添加一个char。
那什么是一个空类呢:
·Has static members /member function
·Has no virtual function
这样的类就是一个空类。
由于编译器对每一个空类都会添加一个char,来保证每一个class对象都具有不同的地址,那么在不同的继承环境下上就会导致一些问题。
我们主要讲两个一个是空类的单一继承,另外一个是空类的虚拟继承:
对于第一种情况,我们用一个空类去继承另外一个空类。
我们已知Empty_A大小为一个字节,那么根据vs的编译结果来看Empty_B大小为四个字节。
对于第二种情况来说如下图
此时A,B,C,D的所占内存大小为1,8,8,12
有的编译器会显示1,8,8,16.
出现这两种情况原因是关于Allgnment的限制,和不同编译器对Allgnment的解决方式不同所导致不同的优化结果。
1,8,8,12.这种情况是现在主流编辑器的情况,为什么这么说呢?
因为对于C++OO来说:
“一个empty virtualbase class,被视为derived interface class object的一部分。”,也就是说我们并不会用empty virtual base class定义任何对象。所以就可以无视c++标准的规定。所以在derived的情况下,并不会占用空间。
接下来说说关于数据成员的绑定(thebinding of data member)
关于数据成员绑定有些东西没必要谈,因为有些成员绑定的演进是由于程序员不同的写法而造成了编译器的对这个行为的“妥协”。只要说一句“对于一个类成员函数的分析会被延迟到"}"的出现才开始分析的”。
关于其他说一下typedef
typedef int length;class a {public:length member;private:typedef long length;};
在这个class中,我们可能会有一些因直觉而失去正确的判断,认为class member length的类型为 long,其实是global typedef。
因此在typedef的定义中应该避免nested(嵌套) typedef。
:using的情况也是和typedef一样。
我们再来看看data member的布局(datamember layout)
//c++class类对象单独享有类成员(no-static),而共享类成员函数。
对于data member的布局我们看看c++11怎么说:
摘自c++11 standrad
No-staticdata members of class with the same access control are allocated so that latermembers has highter addresses with a class object
access(指的是private,public,protected等区段)
而对于相同区段的重复定义则,编译器可以按照自己的方式去定义不同区段的排列顺序,实际上大家没有一个反人类的心去改变顺序,而是选择直接按照区段顺序定义data member。
这里我们不说多态,与多继承,虚拟继承的情况。
谈一下类成员的存取,对于no-static members的存取就一定要谈到面向对象的精髓-多态,说到多态貌似不谈设计模式就感觉少了点什么,好吧,接着类成员的存取接着说,指针调用类成员函数与类成员和直接调用成员
函数与类成员产生的差异与否都是和多态与virtual derive 有关。
关于c++ virtual我可能会花时间,写一篇博文来巩固自己的认知,这里就不再赘述。
对于static members来说,取staticmembers的地址就是取得它位于内存中的地址并不是偏移量,它可以看做是global的。但是被class限制,此时的类具有等效于一个namespace。
关于单一继承与多继承:
对于与单一继承,c++保证在derived class中保证 base class object对象的完整性,这就是说,因为Allgnment而导致的字节扩充也会被继承下来。(空类是其中特殊的一环)
而单一继承的问题是对于派生类的主要问题发生在derived class object向下转换的时候可能需要编译器的介入。
一个多重类的派生对象在将地址指向最左端的base class时候,情况与单一继承相同(因为保证了对象的完整性),而赋予第二个对象的时候就需要调整指针位置。
看个例子:
class A {....};class B :A {...};class C {...};class D :B, C {...};
对于
D想B的转化我们直接将D的地址交给B即可。
而对于向C的转化我们需要做如下操作。
D* d=new …;C* c;c =d;->-> c=(C)((char*)d + sizeof(b));//(这个转化对于现在来说并不是很标准,c++11提供的转化更加专业)
当d为null pointer的时候,就会遇到麻烦,我们稍稍改进一下:
c=d ?(C)((char*)d + sizeof(b)) : 0;
关于虚拟继承,将会在下一篇文章和data members pointer中一并写出。
参考资料:深度探索c++对象模型(侯捷译著),BOOST程序库探秘。 c++11 standrad
与之相关的资料:Bjarne Stroustrup's homepage:http://www.stroustrup.com/index.html
- 探究c++对象模型之data语义学(一)
- 深度探索C++对象模型之Data语义学小测试
- C++对象模型 ch3 Data语义学
- 深度探索C++对象模型----Data语义学
- 深度探索C++对象模型-Data语义学
- C++对象模型--4.Data语义学
- 深度探索C++对象模型之第三章:data语义学中对象布局
- C++对象模型(五):The Semantics of Data Data语义学
- [读书笔记] 深入探索C++对象模型-第三章 Data语义学(上)
- [读书笔记] 深入探索C++对象模型-第三章 Data语义学(中)
- [读书笔记] 深入探索C++对象模型-第三章 Data语义学(下)
- 《深度探索c++对象模型》 学习笔记 - 3 data语义学
- 深度探索C++对象模型复习和学习 第三章 Data 语义学(The Semantics of Data )
- Swift 对象内存模型探究(一)
- C++对象模型 ch4 Function语义学
- C++对象模型 ch6 Running语义学
- 深度搜索C++对象模型 - 数据语义学
- 深度搜索C++对象模型 - 函数语义学
- 调用ShareSDK第三方分享
- Access denied for user 'root'@'localhost' (using password: NO)
- Design Pattern: Singleton
- A:LinkedList实现了List接口; B: AbstractSet实现了Set接口; C: HashSet继承自AbstractSet基类; D: WeakMap继承自 AbstractMap
- final 不能修饰抽象类 方法可以被重载 但不能被重写
- 探究c++对象模型之data语义学(一)
- Android LinearLayout属性
- 多重边框 不用嵌套的多重边框写法
- Leetcode 332. Reconstruct Itinerary
- 51Nod-1464-半回文
- MySQL启动不了,无法启动MySQL服务
- JDK工具(1) jps
- Hard 380题 Insert Delete GetRandom O(1)
- Ubuntu下显卡管理