深度探索C++对象模型--Function语意学
2015-08-05 14:19
579 查看
成员函数调用方式
Nonstatic Member Function(非静态成员函数)
-Nonstatic Member Function设计准则:与一般非成员函数(nonmember function)有相同的执行效率。因此,实际上编译器内部将Nonstatic Member 函数实体转化为对等的nonmember 函数实体。-转换过程:
1. 添加额外this指针,提供数据存取管道
2. 修改函数体内成员数据存取方式,改为使用this指针存取
3. 对函数名字重新“mangling”修饰处理
class A{ public: int x, y; int func(); } int A::func(){ return x+y; } //Nonstatic Member function int A::func(A *const this) //1.添加额外参数this指针 int A::func(A *const this){ return this->x + this->y;} //2.改为由this指针存取成员数据 extern int func_1AFv(A *const this) //3.对函数名进行“mangling”修饰 obj.func() ---> func_1AFv(&obj)
名称特殊处理(name mangling):
member function重载化,以提供独一无二名称,采用该手法。函数名称+类名称+参数数目+参数类型 函数名称 + 类名称+参数数目 + 参数类型
//可能的修饰方法: int Point::foo(float x) ---> int foo_5PointFf(float x) int Point::foo(void) ---> int foo_5PointFv()
Static Member Function(静态成员函数)
-静态成员函数没有this指针: 1. 不用直接存取class中nonstatic members 2. 不能被声明为const, volatile 或者virtual 3. 不需要有class object才能被调用 -Static Member Function会被编译器转化为nonmember形式,实际上该类函数产不多等同于nonmember function。
static int A::func() //静态成员函数 //各种方式调用静态函数,均转换成通过类作用于直接调用 ptr->func()/obj.func()/A::func() --> A::func() //函数mangling修饰 A::func() ---> func_1ASFv() //SFv表示静态成员函数,参数void
Virtual Member Function(虚成员函数)
//1是virtual table slot索引,关联到func函数 ptr->func() -->(*ptr->vptr[1])(ptr) //明确的调用可以抑制虚拟机制 A::func() // 通过该obj调用不支持多态 obj.func() ---> func_1AFv(&obj)
-通过class object调用virtual function的操作会被编译器转换为一般的nonmember member function,不呈现多态。
下面将虚函数的调用。
Virtual Member Functions
c++多态:以一个public base class的指针,寻址出一个derived class object。//调用虚函数,如何在执行期确定func()实体 ptr->func()
编译期间完成的事情:
-给每一个class object安插由编译器内部产生的vptr
-给vtbl每一个virtual function一个固定的slot,在整个继承体系中保持与特定virtual funciton相联
vtbl包含的virtual function有:
-该class所定义的函数实体,包括覆盖base class中的virtual function
-继承自base class的实体,并决定不覆盖
-pure_virtual_called()纯虚函数
单一继承
class Point { public: virtual ~Point(); //slot 1 virtual Point& mult (float) = 0 //slot 2 float x() const {return _x;} virtual float y() const {return 0;} //slot 3 virtual float z() const {return 0;} //slot 4 protected: Point (float x = 0.0); float _x; } class Point2d:public Point { public: ~Point2d(); //slot 1 Point2d& mult (float) //函数覆盖 slot 2 float y() const {return _y;} //函数覆盖 slot 3 protected: float _y; } class Point3d:public Point2d { public: ~Point3d(); //slot 1 Point3d& mult (float) //函数覆盖 slot 2 float z() const {return _z;} //函数覆盖 slot 4 protected: float _z; } //一般来说我们事先并不知道ptr所指对象真正类型 //所以不知道哪个mult实体会被调用,但mult()固定在slot 2中是确定的 ptr->mult() //因此编译器如下转换 //执行期唯一需要做的就是确定哪一个slot 2的实体 (*ptr->vptr[2])(ptr)
多重继承
//编译时期就将指针转移至第二个base class起始地址 Base2 *pbase2 = new Derived; //执行时需要调整pbase2至Derived起始地址 delete pbase2; //该行代码无法在编译时知道pbase2的真实对象,执行时才知道
-多重继承结构如下:Derived会有两个vtbl被编译器产生:(1)主体实体,与base1(最左端base class)共用 (2)次要实体,与base2有关
-三种需要调整指针的情况
1 通过指向base2的指针,调用derived class virtual function。
//编译时期就将指针转移至第二个base class起始地址 Base2 *pbase2 = new Derived; //执行时需要调整pbase2至Derived起始地址 delete pbase2;
2 通过指向derived class的指针,调用第二个base claass中的一个继承而来的virtual function。
//编译时期就将指针转移至第二个base class起始地址 Derived *pder = new Derived; //执行时需要调整pder以指向Base2 subobject pder->mumble; //调用Base2::mumble()
3 三个clone函数实体返回值类型不同
//编译时期就将指针转移至第二个base class起始地址 Base2 *pbase2 = new Derived; //调用Derived* Derived::clone() //需要将pbase2指针调整至Derived class起始处 //返回值时又需要重新调整至Base2 subobject Base1 *pbase2_new = pbase2->clone;
虚拟继承
详见链接:/article/9017516.html
指向Member Function指针
指向nonvirtual function指针
-得到真实地址,但它需要绑定与某个class object上,才能通过它调用。double (Point::*coord) = &Point::x; //nonvirtual function //调用函数 (obj.*coord) () //被编译器转化 (coord)(&obj) //&obj为this指针
-static member function函数地址为普通函数指针,因为没有this指针。
指向virtual function指针
virtual function地址在编译时期是未知的,但是与之相关的vtbl slot的索引值是固定的。所以取virtual function地址只能获得其索引值。class Point{ public: virtual ~Point(); //slot 1 virtual float z(); //slot 2 } float (Point::*pmf) = Point::z; //= 2 Point *ptr = new Point2d; ptr->*pmf; //被编译器转化为 (*ptr->vptr[(int)pmf](ptr));
多重继承下 member function指针
问题:如何区别Member Function指针指向地址还是virtual table索引?方法:修改Member Function指针mptr结构体,mptr->index正负判别。
struct __mptr { int delta; int index; //virtual function时:vtbl索引 nonvirtual时为-1 union{ ptrtofunc faddr; //nonvirtual 时函数地址 int v_offse; } }
相关文章推荐
- list
- [LeetCode] Reverse Linked List II
- C++为了兼容,所以并不是纯面向对象编程语言
- stack
- C++文件操作
- set
- 设计模式之策略模式
- C++常量指针this
- 循环队列的c++类
- C++/G++ 手动扩栈
- C语言之变量类型和存储方式
- VC++自定义消息处理函数2
- MFC/C++/C中字符类型CString, int, string, char*之间的转换
- C++怎么判断一个类存在指定的函数名的函数
- [LeetCode] Partition List
- C++ STL 队列 QUEUE
- C语言实现md5校验
- #Exception#Cpp中Exception类的选择
- C语言数组参数与指针参数
- C++ 组合函数