分享
 
 
 

深入探索C++对象模型 之 Function语意学

王朝c/c++·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

名称的特殊处理(Name Mangling)

如member:

class bar{public: int ival; …}

class foo :public class bar {public: int ival; …}

经处理后:

class foo{

public:

int ival_3bar;

int ival_4foo;

}

如function:

class point {

public:

void x (float newX);

float x();

}

经处理后:

class Point {

public:

void x_5PointFf (float newX);

float x_5PointFv ();

}

把参数和函数名称编码在一起,编译器于是在不同的被编译模块之间达成了一种有限形式的类型检验(“返回类型”的声明错误没办法检查出来)。

Nonstatic Member Functions (非静态成员函数)

需经过内部转化,步骤:

1. 改写函数原型以安插一个额外的参数到member function 中,用以提供一个存取管道,使class object 得以调用该函数。该额外参数被称为this 指针:如

Point3d Point3d::magnitude(Point3d *const this)

如果member function 是const , 则变成:

Point3d Point3d::magnitude(const Point3d *const this)

2.将每一个“对nonstatic data member 的存取操作”改为经由this 指针来存取。

3.将member function 重新写成一个外部函数。对函数名称进行“mangling”处理,使它在程序中成为独一无二的语汇。

而函数的调用操作也都必须转换。

如:obj.magnitude() 变成了:magnitude_7Point3dFv(&obj);

Static Member Function (静态成员函数)

如:obj.normalize();ptr->normalize();将都被转换为一般的nonmember 函数调用,

象这样:normalize()_7Point3dSFv();

Static member functions 的主要特性就是它没有this指针,次要特性统统根源于其主要特性:

1. 它不能直接存取其class中的nonstatic members。

2. 它不能够被声明为const,volatile 或 virtual。

3. 它不需要经由class object 才被调用——虽然大部分时候它是这样被调用 的!

如果class object 是因为某个表达式而获得的,这个表达式仍然需要被评估求值;

如:if ( foo ().objcet_count () > 1) …

被转换为:(void) foo (); if ( Point3d::object_count() > 1) …

如果取一个static member function 的地址,获得的将是其在内存中的位置,也就是其地址。由于static member function 没有 this 指针,所以其地址的类型并不是一个“指向class member function 的指针”,而是一个“nonmember 函数指针”,也就是说:

&Point3d::object_count();会得到一个数值,类型是:unsigned int (*) ();

而不是:unsigned int (Point3d::*) ();

Virtual Member Function (虚拟成员函数)

如:ptr->normalize();将被内部转化为:(*ptr->vptr[1])(this);

明确的调用操作(explicitly invocation)会压制虚拟机制,其决议方式和nonstatic member function一样。如:register float mag = Point3d::magnitude();//magnitude是virtual function

在C++中,多态(polymorphism)表示“以一个public base class 的指针(或reference),寻址出一个derived class object”的意思。

识别一个class 是否支持多态,唯一适当的方法就是看看它是否有任何virtual function。

有这样的调用:ptr->z();

为了在执行期调用正确需要知道两点:

1. ptr所指对象的真实类型。这可使我们选择正确的z()实体;

2. z() 实体位置,以便我能够调用它。

实现上,可以在每一个多态的class object 身上增加两个members:

1. 一个字符串或数字,表示class 的类型;

2. 一个指针,指向某表格,表格中带有程序的virtual functions 的执行期地址。

为了在执行期找到virtual function 的地址,需要两个步骤:

1. 为了找到表格,每一个class object 被安插上一个由编译器内部产生的指针,指向该表格。

2. 为了找到函数地址,每一个virtual function 被指派一个表格索引值。

单重继承下的virtual functions:

一个class 只会有一个virtual table。每一个table 内含其对应的class object 中所有active virtual functions 函数实体的地址。这些active virtual functions 包括:

1.这个class 所定义的函数实体。它会改写(overriding)一个可能存在的base class virtual function 函数实体。

2.继承自base class 的函数实体。这是在derived class 决定不改写virtual function 时才会出现的情况。

3.一个pure_virtual_called() 函数实体,它既可以扮演 pure virtual function 的空间保卫者角色,也可以当做执行期异常处理函数(有时会用到)。

调用pure virtual function ,通常会结束掉程序。

多重继承下的virtual functions:

在多重继承中支持virtual functions,其复杂度围绕在第二个及后继的base classes 身上,以及“必须在执行期调整this 指针”这一点。

如:Base2 *Pbase2 = new Derived;新的Derived 对象的地址必须调整,以指向其Base2 subobject.编译时期会产生以下的码:

//转移以支持第二个base class

Derived *temp = new Derived;

Base2 *Pbase2 = temp ? temp + sizeof (Base1 ) : 0;

当程序员要删除Pbase2所指的对象时:指针必须被再一次调整,以求再一次指向Derived 对象的起始处。

在多重继承之下,一个derived class 内含n-1 个额外的virtual tables,n 表示其上一层 base classes 的数目。

1.一个主要实体,与Base1共享(Vtbl_Derived).

2.一个次要实体,与Base2 有关(Vtbl_Base2_Derived).

允许一个virtual function 的返回值类型有所变化,可能是base type,也可能是 publicly derived type。

虚拟继承下的virtual function:

有个建议是,不要在一个virtual base class 中声明nonstatic data members。

指向member function 的指针(Pointer-to-Member Functions)

取一个nonstatic data member 的地址,得到的结果是该member 在class 布局中的bytes 位置(再加1)。它是一个不完整的值,它需要被绑定于某个class object 的地址上,才能够被存取。

取一个nonstatic member function 的地址,如果该函数是nonvirtual ,则得到的结果是它在内存中真正的地址。这个值也是不完全的,它也需要被绑定于某个class object 的地址上,才能够通过它调用该函数。所有的nonstatic member functions 都需要对象的地址(以参数this 指出)。

一个指向 member function 的指针,如:

double (Point::*pmf) ()=&Point::x;

x 可以是virtual 或者是nonvirtual 的。但是被解释的结果不一样:

((( int ) pmf ) & ~127 ) ? ( *pmf ) ( ptr ) : ( *ptr->vptr[ ( int )pmf ] ( ptr ) )

Inline Functions(内联函数)

处理inline 函数,有两个阶段:

1. 分析函数定义,以决定函数的“intrinsic inline ability”(本质的inline 能力)。“intrinsic”(本质的,固有的)一词在这里意指“与编译器有关”。如果函数因其复杂度,或因其建构问题,被判断不可成为inline,它会被转为一个static 函数。

2. 真正的inline 函数扩展操作是在调用的那一点上,这会带来参数的求值操作(evaluation)以及临时性对象的管理。

形式参数:

一般而言,面对“会带来副作用的实际参数”,通常都需要引入临时性对象。

即如果实际参数是一个常量表达式,可以在替换之前先完成求值操作;后继inline 替换,就可以把常量直接“绑”上去。如果既不是个常量表达式,也不是个带有副作用的表达式,那么就直接代换之。

局部变量:

如果inline 函数以单一表达式扩展多次,那么每次扩展都需要自己的一组局部变量。如果inline 函数以分离的多个式子被扩展多次,那么只需一组局部变量,就可以重复使用(因为它们被放在一个封闭区段中,有自己的scope)。

如:单一表达式:

minval = min ( val1, val2 ) + min ( foo (), foo () + 1);

分离的多个表达式:

minval_1 = min ( val1, val2 );

minval_2 = min ( val3, val4 );

Inline 函数对于封装提供了一种必要的支持,可以有效存取封装于class 中的nonpublic 数据。它同时也是C 程序中大量使用的#define (前置处理宏)的一个安全代替品——特别是如果宏中的参数有副作用的话。然而一个inline 函数如果被调用太多次的话,会产生大量的扩展码,使程序的大小暴涨。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有