深度探索C++对象模型 4.Function语意学

C++支持三种类型的成员函数:static、nonstatic和virtual,每一种类型被调用的方式都不相同。

4.1 Member的各种调用方式

非静态成员函数

设计准则
 C++的设计准则之一就是:非静态成员函数至少和一般的非成员函数有相同的效率。

成员函数转化为非成员函数
在这里插入图片描述

转化步骤
1.改写函数原型,安插this指针到成员函数中(this指针指向对象数据的首地址)

//non-const nonstatic member函数的扩张过程
Point3d
Point3d::magnitude(Point3d* const this)
 
//如果member function是const,则变成:
Point3d
Point3d::magnitude(const Point3d* const this)

2.将“对非静态数据成员的存取操作”改为经由this指针来存取:

{
	return sqrt(_this->x * _this->_x +
				_this->y * _this->y +
				_this->z * _this->z); 
}

3.将成员函数重新写成一个外部函数,将函数名称经过“mangling(名称改写)”处理,使它在程序中成为独一无二的词汇。

extern magnitude_7Point3dFv(register Point3d* const this);

函数的调用转化为:

obj.magnitude();
//经编译器转换
magnitude_7Point3dFv(&obj);
 
ptr->magnitude();
//经编译器转换
magnitude_7Point3dFv(ptr);

转化结果

float ClassA::func(){
    return _x + _y;
}
//被改写成类似这样
float func_ClassA(ClassA *this){//被修改的函数名在不同编译器中有不同策略,不过对编程来说影响不大,想要了解命名策略可以上网查找。
    return this->_x + this->_y;
}

名称的特殊处理
成员名加类名,如果是函数再加上参数类型的编码(区别重载函数),可以形成独一无二的名称。

虚拟成员函数

转化

ptr->normalize();
 
//内部转化
(*ptr->vptr[1])(ptr);

●vptr表示指向虚表的指针
●1代表次函数在虚表中的索引值
●ptr表示this指针

显示类名调用/对象调用
这两种调用都用不到virtual机制,所以效率比较高

静态成员函数

主要特性
没有this指针,所以:
●不能存取非静态成员
●不能被声明为const、volatile或virtual
●不需要经过对象进行调用,不过大部分时候还是通过对象调用

无对象时的调用
((point3d*) 0)->object_count();将0转换为该类对象的指针,提供this指针来调用函数。

取静态成员函数地址
获得的是在内存中的位置,也就是地址,由于静态成员函数没有this指针,所以地址的类型并不是一个“指向类成员函数的指针”,而是一个“非成员函数指针”。

&Point3d::object_count();
会得到 unsigned int(*)();
而不是 unsigned int (Point3d::*)();

静态成员函数的用途
没有this指针,差不多等同于非成员函数。所以可以成为一个callback函数,可以应用在线程方面。

pthread_create的函数原型中第三个参数的类型为函数指针,指向的线程处理函数参数类型为(void*),若线程函数为类成员函数,则this指针会作为默认的参数被传进函数中,从而和线程函数参数(void*)不能匹配,不能通过编译。静态成员函数就没有这个问题,里面没有this指针。

4.2虚拟成员函数

实现执行期类型判断的条件

调用方法
 下面的操作需要获得ptr在执行期的某些相关信息。

ptr->z();

效率方面
真正需要执行期类型判断时这份信息就存在,不需要就不存在,不然一直都存在的话会造成效率低下。

解决方法
●需要知道ptr所指对象的真实类型,这可使我们选择正确的z()实例。------>一串字符或数字,表示class的类型
●z()实例的位置,以便可以调用------->一个指针指向某表格,表格中持有程序的虚函数的执行期地址。
 为了找到表格,每一个类对象中安插一个编译器内部产生的指针(vptr),指向表格。
 为了找到函数地址,每一个虚函数指派一个表格索引值。

 执行期只需要在特定的虚函数表槽(记录执行期地址)中激活虚函数。
在这里插入图片描述
编译器转化
如何在编译时期设定虚函数的调用?
●调用z()时,不知道ptr所指对象的真正类型,但是知道经由ptr可以存取到该对象的虚函数表
●不知道哪一个z()会被调用,但是知道每一个z()函数地址都在slot4中。

 唯一在执行期才知道的是:slot4指向的是哪个z()函数?

多重继承下的virtual functions

问题:
在这里插入图片描述
如何调整
见书

虚拟继承下的虚函数

 建议不要在一个virtual base class中声明非静态成员变量,否则会越来越复杂。

4.3函数的效能

非成员、静态成员和非静态成员函数都被转化为完全相同的形式,所以三者的效率完全相同

4.4 指向成员函数的指针

取地址

●非静态成员变量:成员在class布局中的bytes位置
●非静态成员函数:如果是非虚函数,得到的结果是在内存中真正的地址,但是这个地址也不完全,需要被绑定于某个对象身上,才能够通过它调用该函数。所有的非静态成员函数都需要对象的地址(this指出)
●虚成员函数:在虚表中的索引值,因为地址在编译时期是未知的。

4.5 Inline Functions

作用
 对于封装提供了一种必要的支持,可以有效存取封装于class中的nonpublic数据。
 是#define的安全替代品

缺点
 如果inline程序被调用太多次,会产生大量的扩展码,使程序大小暴涨。
 参数带有副作用,以一个单一表达式作多重调用,或者在inline函数中有多个局部变量,都会产生临时性对象,会更复杂。

inline int min(int i, int j){
	return i < j ? i : j;
}
这样调用时:会产生临时变量
minval = min(foo(), bar() + 1);
变为:
int t1, t2;
minval = (t1 = foo()), (t2 = bar() + 1), t1 < t2 ? t1 :t2;
inline int min(int i, int j){
	int minval = i < j ? i : j;
	return minval;
}
这样调用,会产生局部变量:
minval = min(val1, val2);
变为:
int _min_lv_minval;
minval = (_min_lv_minval = 
			val1 < val2 ? val1 : val2),
			_min_lv_minval;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《深度探索C++对象模型》是由侯捷所著的一本经典的C++图书,该书于2012年由机械工业出版社出版。本书的主要内容涵盖了C++对象模型的深入解析和探讨。 在书中,作者详细讲解了C++中的对象模型和相关的概念,如类、对象、继承、多态等。作者首先介绍了C++对象模型的基本概念和特点,包括对象的内存布局、虚函数表和虚函数指针等。然后,作者深入探讨了C++中的继承机制和多态性,包括单继承、多继承、虚继承等。作者还详细介绍了虚函数的实现原理和使用方法。 在书中,作者对C++对象模型的实现细节进行了深入的剖析,包括成员变量和成员函数的内存布局、函数指针和成员函数指针的用法等。同时,作者还讨论了C++中的一些高级特性,如模板、内存管理和异常处理等。通过对C++对象模型深度探索,读者可以更好地理解C++的内部机制和原理,提高程序设计和开发能力。 《深度探索C++对象模型》适合具有一定的C++编程基础的读者阅读,尤其是对C++对象模型感兴趣的读者。通过阅读本书,读者可以进一步了解C++的底层实现和运行机制,从而提高自己的编程能力和代码质量。此外,本书还提供了大量的示例代码和实践案例,可以帮助读者更好地理解和应用所知识。 总之,《深度探索C++对象模型》是一本深入探讨C++对象模型的经典著作,通过对C++的底层实现和内部机制的剖析,帮助读者深入理解C++编程语言,并提高自己的软件开发能力。 ### 回答2: 《深度探索C++对象模型》是由Stanley B. Lippman于1994年所著的一本经典畅销的C++书籍,该书详细介绍了C++对象模型的内部实现细节。 C++对象模型是指C++编译器在处理对象、继承、多态等面向对象特性时所采用的具体实现方式。这本书通过对对象模型的剖析,帮助读者深入理解C++的内部工作原理,从而写出更高效、更可靠的C++代码。 在《深度探索C++对象模型》中,作者首先介绍了对象、虚函数、继承等C++核心概念,然后详细讲解了C++对象模型的构建过程,包括对象布局、成员函数指针、虚函数表等。作者逐步深入地剖析了C++对象模型在内存中的表示方式,解释了为什么C++可以支持如此强大的面向对象特性。 此外,本书还探讨了一些高级主题,如多重继承、虚拟继承、构造函数和析构函数的执行顺序等。对于想要深入C++的读者来说,这本书提供了一些宝贵的技术手册和实用的经验。 尽管《深度探索C++对象模型》的出版时间是1994年,但它仍然被广泛认可为C++对象模型的经典之作。在2012年时,由于C++的发展和演进,也许一些内容已经有些过时,但很多基本概念和原理仍然适用。 总而言之,《深度探索C++对象模型》是一本值得阅读的C++经典著作,通过深度探索C++对象模型,读者可以更加深入地了解C++的内部工作原理和实现方式,提升自己的开发技能。 ### 回答3: 《深度探索C++对象模型》是一本于2012年出版的书籍。该书的作者Andrews和Sorkin以全面的角度深入探讨了C++对象模型。该书重点介绍了C++中的对象表示、虚函数、继承、多重继承、构造函数、析构函数等内容,以及与之相关的语法、原理和底层实现。 这本书为读者揭示了C++对象模型的奥秘,让人更加深入地理解C++语言中的类和对象。作者通过分析对象布局、虚函数表、虚函数调用、多继承中的数据布局和函数调用等等,解释了C++对象模型的实现机制。 在读者了解C++对象模型的基础上,该书还介绍了如何有效地利用对象模型来提高程序的性能。作者讨论了虚函数的成本以及如何减少虚函数调用的开销,提供了一些优化技巧。此外,书中还对C++的构造函数和析构函数进行了深入的讨论,详细解释了构造函数和析构函数的执行机制和注意事项。 总的来说,《深度探索C++对象模型》是一本深入剖析C++对象模型的重要参考书籍。通过阅读该书,读者可以更加全面地了解C++的类和对象的实现原理,对于理解C++语言的底层机制和优化程序性能具有积极的作用。无论是对于初者还是有一定C++基础的开发人员来说,该书都是一本值得阅读的重要参考书。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值