[温故而知新] 《深度探索c++对象模型》——对象方法成员
来源:互联网 发布:网络女主播大尺度直播 编辑:程序博客网 时间:2024/05/01 14:03
本节的复杂点,在于对virtual function的支持上。
先从简单的几种function入手
1.non member function
2.static member function
3.non static member function
第一种是最常见的 non member funcion:
//在一个地方定义returnValue functionName(argumentList){ //function body}//在另一个地方声明extern returnValue functionName(argumentList);
第二种static member function
class ClassName{public: static returnValue functionName(argumentList);}//调用ClassName::functionName(...);
static member function 与 non member function非常相似,实际上,编译器就是通过类名和函数签名等把static member function 转换为 non member function。
第三种 non static member function
class ClassName{public: returnValue functionName(argumentList);}
第三种与第二种也是非常类似,最终编译器也是把它转为一个non member function。与static member function 区别在于,non static member function 会在转换的过程中修改函数的签名,加入”this”指针。
比如:
class Point{public: int x; int y; void setX(int n);};void Point::setX(int n){ x = n;}//转化为类似如下的方法,下面的函数名命名规则,各家编译器不尽相同:void Point_setX_int(Point *const this,int n){ this->x = n;}//有了上面这一步的转化,那么那些执行方法调用的地方,编译器也会进行修改:Point point;point.setX(1); //转化为类似 Point_setX_int(&point,1);
上面三种方式,效率是一致的。
virtual member functions
2.1、单继承下的virtual member functions
class Animal{public: virtual void say() =0; //纯虚函数};class Dog:public Animal{public: void say();};class Cat:public Animal{public: void say();};void Dog::say(){ cout << "wang~ wang~ wang~" << endl;}void Cat::say(){ cout << "miao~ miao~ miao~" << endl;}
画个图了解下内存布局:
注意上图种的vptr table,这些是编译器根据我们的代码生成的辅助结构,vptr table存的是一些函数指针。
这里我们假设:
//Dog::say() 编译器转化后的non member funtion为 void Dog_say_void(Dog const *thiz){ cout << "wang~ wang~ wang~" << endl;}//Cat::say() 编译器转化后的non member function为void Cat_say_void(Cat const *thiz){ cout << "miao~ miao~ miao~" << endl;}
Dog dog;Cat cat;Animal *ptr;//1.使用指针调用的虚函数ptr = &dog;ptr->say(); //wang~ wang~ wang~ptr = &cat;ptr->say(); //miao~ miao~ miao~/** ptr->say()的编译器转化(*ptr->vptr[index])(ptr)*///2.使用对象调用的虚函数dog.say();//编译器转化为 Dog_say_void(&dog);cat.say();//编译器转化为 Cat_say_void(&cat);
注意比较上面两种调用方式,使用指针调用virtual 方法,可能需要经过一层间接查表得到最终调用的方法,因为在编译期无法确定ptr指向的对象实际是哪种类型,而使用对象调用virtual 方法,则不需要中间那一层查表,因为编译器在编译期就已经知道这个对象是哪种类型。
2.2、多继承下的virtual member functions
class Base1{public: virtual ~Base1(); virtual void speakClearly(); virtual Base1 *clone() const;protected: float data_Base1;};class Base2{public: virtual ~Base2(); virtual void mumble(); virtual Base2 *clone() const;protected: float data_Base2;};class Derived :public Base1, public Base2{public: virtual ~Derived(); virtual Derived *clone()const;protected: float data_Derived;};
画个图了解下内存布局:
注意上图中右下角 Derived的内存布局,是优化后的,也就是把Derived 的 vptr去掉,与Base1用同一个vptr,同时修改vptr table。
同时注意到,在上图的多重继承中的Derived,有三处地方需要涉及到“this”指针的调整。
1.virtual destructor
2.多重继承中第二个或之后的Base Class 继承下来的virtual function。这里的例子为图中标红的Base2::mumble()。
3.一个语言扩充性质:允许一个virtual function的返回值类型有所变化,可能是base type,也可能是 public derived type。 这里的例子为图中标红的clone()方法。
为什么需要调整this指针呢?因为non member function的第一个参数为this指针,比如
Base2 *ptr = new Derived;delete ptr;//这里实际调用的是Derived::~Derived()而不是Base2::~Base2();//也就是实际上的调用类似 Derived_destrutor(ptr),显然这里的ptr是不对的,需要调整为Derived_destrutor(ptr-sizeof(Base1))
关于this指针的调整,书中提到微软采用了”thunk”技术,我根据书中例子画了个图,更容易理解:
上图中,红色虚框中就用到了“thunk”。
那么什么是 “thunk”技术呢?
简单地理解就是一个代码片段,这个代码片段的目的就是修改某些参数,然后通过一个jmp指令跳转到目标的代码去。
具体可以参考:
《C++ Tips: Adjustor thunk: what is it, why and how it works》
《Adjustor thunks》
《C++ 的THUNK技术》
2.3、虚拟继承下的virtual member functions
这个与多重继承下的virtual member functions类似。
书中提到一个建议:“不要在一个virtual base class 中声明nonstatic data members”。
指向 member functions 的指针
本节的复杂点,也是在于virtual member function 在多重继承和虚拟继承下的支持。
比如:
class Point{public: float x(); virtual float z();};//Point *ptr = new Point;float (Point::*pmf)() = &Ponit::z;(ptr->*pmf)();//编译器转化为:(*ptr->vptr[(int)pmf])(ptr)pmf = &Point::x;(ptr->*pmf)();//编译器转化为:(*pmf)(ptr)
可以看到,同样是执行(ptr->*pmf)()
,编译器要根据情况进行不同的转化。书中提到了一个结构用于支持member function指针:
struct _mptr{ int delta; int index; union{ ptrtofunc faddr; int v_offset; }}
书中也没详细讲解这一节,不过可以简单的理解,就是在处理上面提到的各种对于member function pointer的支持,使用这个结构中相应的字段进行标识、支持即可。
inline function
注意几个副作用:
//1.形式参数的副作用inline int min(int i,int j){ return i<j?i:j;}int minval;minval = min(foo(),bar()+1);//转化为int t1;int t2;minval = (t1 = foo(),t2 = bar()+1),t1<t2?t1:t2;//2.局部变量inline int min(int i,int j){ int minval = i<j?i:j; return minval;}int m;m = min(val1,val2);//转化为int __min_minval;m = (__min_minval = val1<val2?val1:val2),__min_minval;
const相关小知识点
class Point{public: int getX() const; //限制该方法只读取而不修改Point对象相关数据 void setX(int n);private: int x;}//限制ptr不能被修改,比如不允许 ptr = otherPtr;Point *const ptr//限制ptr指向的对象不能被修改,比如不允许调用 ptr->setX(0)const Point *ptr//限制ptr不能被修改,并且不能修改ptr指向的对象。const Point *const ptr
- [温故而知新] 《深度探索c++对象模型》——对象方法成员
- [温故而知新] 《深度探索c++对象模型》——对象数据成员的内存布局
- [温故而知新] 《深度探索c++对象模型》——构造函数
- [温故而知新] 《深度探索c++对象模型》——站在对象模型的尖端
- [温故而知新] 《深度探索c++对象模型》——构造、析构、拷贝的语义
- [温故而知新] 《深度探索c++对象模型》——运行期语意
- 深度探索C++对象模型
- 《深度探索C++对象模型》—关于对象(Object Lessons)
- 【C++】深度探索C++对象模型之虚拟成员函数(virtual member function)
- PHP5.0对象模型深度探索之类的静态成员
- 深度探索C++对象模型——学习笔记1
- 深度探索 C++对象模型——读书笔记
- 《深度探索c++对象模型》——上篇
- 深度探索C++对象模型——构造函数
- 深度探索C++对象模型——学习笔记3
- 深度探索c++对象模型——读书笔记(一)
- 深度探索c++对象模型——读书笔记(二)
- 深度探索C++对象模型——Function语意学
- HDU-A+B Problem 的Java题解 用Java语言做ACM的注意事项
- c语言数据结构实现后缀表达式求值
- HDOJ 4548 美素数
- 【LeetCode从零单刷】Convert Sorted List to Binary Search Tree
- Sprintf--powerful function
- [温故而知新] 《深度探索c++对象模型》——对象方法成员
- 编译原理(六) LL(1)文法分析法(分析过程的C++实现)
- ListView学习
- pyopengl 学习日志(1)--配置环境
- 欢迎使用CSDN-markdown编辑器】
- maven +SSH日记(1)
- git服务器搭建
- 【HTML5+css3】学习笔记之html5介绍
- Contest1040 - 第三届“图灵杯”NEUQ-ACM程序设计大赛(个人赛) C: 橙子姐姐的围棋