Data 语义学(1)
来源:互联网 发布:mysql定时任务 编辑:程序博客网 时间:2024/06/06 11:32
一、Data Member 的绑定(The binding of Data Member)
1 extern float x; 2 3 class Point3d 4 { 5 public: 6 Point3d( float, float, float); 7 float X() const { return x; } 8 void X( float new_x ) const { x = new_x; } 9 // ...10 private:11 float x,y,z; 12 };
请问 Point3d::X()传回哪一个x?是class 内部那个还是外部(extern )的那个?大家肯定都会说传回 class 内部的那个,这个回答是真正确的。但是在早期的c++中可不一定哦,早期的C++的取用操作会指向 global x object,这出乎大家的意料。那么早期是如何预防这种错误呢?有以下两种办法:
(1). 将所有的data member 定义到 class 声明的起始处,以确保正确的绑定,如下:
1 extern float x; 2 3 class Point3d 4 { 5 float x,y,z; 6 public: 7 Point3d( float, float, float); 8 float X() const { return x; } 9 void X( float new_x ) const { x = new_x; }10 // ... 11 };
(2). 把所有的 inline function,不管大小都放在 class 声明之外,即将 member functions 放在class 类里面声明,放到 class 外面进行定义,这里就不举例!
而今天的代码完全不用像上面那样需要进行考虑,因为现在的编译器对 member functions 的分析会直到整个 class 的声明都出现了才开始。因此在一个 inline member function 函数体内的一个 data member 绑定操作,会在整个 class 声明完成之后发生。但是,对于 member function 的 argument list 并不为真哦!请看下面这个例子:
1 #include <iostream> 2 3 using namespace std; 4 5 typedef int length; 6 7 class A 8 { 9 private:10 typedef float length;11 length num;12 public:13 void setNum( length _num )14 {15 num = _num;16 }17 18 };19 20 int main()21 {22 system("pause");23 }
这个代码并没有运行结果,可以通过编译!但是编译器会给出一个提醒:
警告 1 warning C4244: “=”: 从“length”转换到“A::length”,可能丢失数据
这是为什么呢?因为你的成员变量 num 定义的是 float 型,而你的 setNum() 的参数 _num 是 int 型!咋进行赋值时会进行强制转化,这样编译器会给出如上的警告。由此可说明:对于 member function 的 argument list 并不是取用 class 的 typedef 的 length 而是 全局变量 length,所以在写这样的代码要小心了哦。如果你想要 argment list 的也是用 clas 内的 length ,就把内嵌的 typedef 定义放到他要被用到的地方的前面即可咯!
二、Data Member 的布局(Data Member Layout)
nonstatic data members 在 class object 中排列的顺序将和其被声明的顺序一致,任何的static data members都不会被放到对象布局之中。而是存放在程序的 数据段(data segment)而与个别的 class 无关。C++的标准是要求在同一个访问级别(也就是 public、private、protected)中,members 的排列只需符合“较晚出现的 members 在 class object 中具有较高地址“,并没要求他们是连续排列的。那么什么东西会被介于被声明的 members 之间呢?
a. members 的边界调整(alignment) 可能就需要填补一些 bytes. 这样就会隔开两个相连的member啦。
b. 编译器可能会合成一些内部使用的 data members 以支持整个对象模型。vptr 就是这一类东西,虽然没规定它放在哪个位置。但是一般 vptr 会被放在 class object 的声明的 members 的最后,不过也有编译器会把 vptr 放在 class object 的最前端---不太可能会插到 members 之间啦。
三、Data Member 的存取
(1). static data members
我们之前的博文说道不管是没有 class object 、有一个class object 或者 n 个object 这个类的 static data members 都已经存在于程序的 data segment 中了(前提是你得定义了这些 static data members 哈),并且只有一份!大家知道 static data members 可以通过class 的 "::"访问,也可以通过 class object 的"."访问,其实别看他和其他nonstatic 成员一样 通过"."访问,其实它根本不像 nonstatic data members 一样存储在 class object 中啦。这样只是为了方便操作,其实通过"::"访问才是原汁原味的!!!
既然 static data member 都是一份实体存在 程序的 datasegment 中,那么如果一个程序中的两个类有了同样名字的 static data member 就会导致名称冲突,怎么办?不要怕,编译器会对每个 static data member 进行编码(这种手法叫做:name-mangling),以获得一个独一无二的程序识别代码。当然,每个编译器的 name-mangling 做法都不一样,但无论怎么样他们要做的莫非一下两点:
a. 一种算法,推导出独一无二的名称。
b. 万一预编译系统(或编译工具)必须和使用者交谈,那些独一无二的名称就可以轻易的被推到回到原来的名称。(比如报错,提示说你这个 static data member 哪里错误,在给出名字的时候当然是用程序员的命的名称而不是编码后的名称!)
(2). nonstatic data members
nonstatic data members 的大小被存放在一个 class object中,并通过 "." 访问。看下面这个例子:
1 #include <iostream> 2 3 using namespace std; 4 5 typedef int length; 6 7 class A 8 { 9 public:10 virtual void foo(){};11 int num1,num2,num3;12 };13 14 int main()15 {16 A a;17 A *pa = &a ;18 printf(" &A::num2 = %p\n",&A::num2);19 cout << &a << endl;20 cout << &a.num2 << endl;21 cout << &(pa->num2) << endl;22 return 0;23 }
以下是输出结果:
我来解释一下:第一行是data member num2 在class 中的偏移量。第二行是 class A 在内存中的真实地址,第三行和第四行都是num2在内存中的真实地址。
大家发现图中的:0012FF40( num2 的地址 ) = 0012FF38( a 的首地址) + 00000008( num2 在 class A 中的偏移量); 没?
所以你不管是通过 class object 的 "." 访问或者通过class pointer 的 "->" 访问nonstatic data member,编译器都是通过:class object 的首地址 + 该 data member 在class 中的 offset (偏移量)。注意:在通过 class pointer ( 类指针)访问 nonstatic data member的时候,如果该 nonstatic data member 是 virtual base classs 的 data member ,那情况会有所不同哦!不过不用担心---虚继承总是不同于其他情况(具体请看 Data 语义学(2) 中对各种情况的介绍),我们多多注意就行了!
- Data 语义学(1)
- Data 语义学(2)
- 第三章 Data语义学
- C++对象模型 ch3 Data语义学
- 深度探索C++对象模型----Data语义学
- 深度探索C++对象模型-Data语义学
- C++对象模型--4.Data语义学
- 构造函数语义学之程序转化语义学(1)
- 《深度探索c++对象模型》 学习笔记 - 3 data语义学
- 深度探索C++对象模型之Data语义学小测试
- 探究c++对象模型之data语义学(一)
- 形式语义学-chapter 1 specifying syntax
- C++对象模型(五):The Semantics of Data Data语义学
- Inside the C++ Object Model 学习笔记 第三章 Data语义学
- 深度探索C++对象模型之第三章:data语义学中对象布局
- [读书笔记] 深入探索C++对象模型-第三章 Data语义学(上)
- [读书笔记] 深入探索C++对象模型-第三章 Data语义学(中)
- [读书笔记] 深入探索C++对象模型-第三章 Data语义学(下)
- 构造函数语义学之Copy Constructor构建操作(1)
- 构造函数语义学之Copy Constructor构建操作(2)
- 构造函数语义学之程序转化语义学(1)
- 构造函数语义学之程序转化语义学(2)
- 一个类到底有多大?
- Data 语义学(1)
- SOAP 简介(2)
- Data 语义学(2)
- __builtin_expect详解
- TCP连接的建立和终止
- TCP/IP学习(四)TCP缓冲区大小及限制(转)
- POJ 2229 Sumsets (简单DP)
- asp.net分页问题
- Function语义学之member function