大部分内容源自inside C++ object model一书,仅供学习使用
C++支持3种类型的成员函数: static, nonstatic, and virtual.
One C++ design criterion is that a nonstatic member function at a minimum must be as efficient as its
analogous nonmember function
C++设计的一个准则是非静态成员函数至少要与类似的非成员函数一样高效
This is achieved by internally transforming the member instance into the equivalent nonmember instance.
成员实例在内部会转换成等价的非成员实例
(即成员函数在内部会被转换成等价的非成员函数)
Name Mangling
名字改编
这个在深入理解计算机系统第7章也有介绍
In general, member names are made unique by concatenating the name of the member with that of the
class. For example, given the declaration
class Bar { public: int ival; ... };
ival becomes something like
// a possible member name-mangling
ival__3Bar
看到这里时突然想到当父类与子类均定义同名成员时候是如何处理
(C++ primer第4版 15.5.2对此有所介绍)
#include<iostream>
using namespace std;
class Base{
public:
Base()
{
this->val=0;
}
Base(int val)
{
this->val=val;
}
int val;
int Get(){return val;}
};
class Derived:public Base{
public:
int val;
Derived(int val){this->val=val;}
int Get(int &v)
{ v=this->Base::val;
return this->val;
}
};
int main(){
Base a(5);
Derived d(8);
int i;
cout<<d.Get(i)<<endl;
cout<<i<<endl;
//output 8 0
}
上面程序父类与子类均定义了int类型的成员val,当派生类成员与基类成员重名时,将屏蔽对基类成员的直接访问
必须通过作用域操作符。比如上面程序中为了访问基类的val成员使用了Base::val
class Bar { public: int ival; ... };
ival becomes something like
// a possible member name-mangling
ival__3Bar
Why does the compiler do that? Consider this derivation:
class Foo : public Bar { public: int ival; ... };
Remember that the internal representation of a Foo object is the concatenation of its base and derived class
members:
// Pseudo C++ Code
// internal representation of Foo
class Foo { public:
int ival__3Bar;
int ival__3Foo;
...
};
通过name mangling便可以区分了基类与子类中重名的成员
重载的函数在编译器中的表示,比如下例
class Point { public:
void x( float newX );
float x();
...
};
在编译器中表示为(注:函数名中还加入了参数信息function signature)
class Point { public:
void x__5PointFf( float newX );
float x__5PointFv();
...
};
If normalize() were a virtual member function, the call
ptr->normalize();
would be internally transformed into
( * ptr->vptr[ 1 ])( ptr );
vptr represents the internally generated virtual table pointer
1 is the index into the virtual table slot associated with normalize().
ptr in its second occurrence represents the this pointer.
ptr的第二次出现代表this指针(编译器对函数的内部表示中参数一般有个this指针)
// explicit invocation suppresses virtual mechanism
register float mag = Point3d::magnitude();
mgnitude是个虚函数,用作用域操作符抑制虚函数机制
静态成员函数不能声明成 const, volatile,或者virtual
static member function is without a this pointer
静态成员函数调用没有this指针
4.2 Virtual Member Functions
虚成员函数
the class-specific virtual table that contains the addresses of the set of active virtual functions for the class and the vptr that addresses that table inserted within each class object
特定类的虚表包含一组类的活动的虚拟函数的地址和插到每个对象内的索引这张虚表的vptr指针。
注:若该类包含虚函数,则该类的对象中会插入用于索引虚表的vptr指针
(比如下图中Point对象pt中便插入了vptr指针)
ptr->z();
为了支持多态,需要知道ptr运行时的类型信息。
一种可能的解决方案是在ptr指针中包含额外信息(比如对象类型的编码信息),但它会增加指针的开销,
并且破坏与C之间的链接兼容性
So the presence of at least one virtual function is the criterion for identifying those classes requiring additional
runtime information.
为了找到虚表
1. To find the table, an internally generated virtual table pointer is inserted within each class object.
2. To find the function's address, each virtual function is assigned a fixed index within the table.
The virtual table is generated on a per-class basis. Each table holds the addresses of all the virtual function
instances "active" for objects of the table's associated class. These active functions consist of the following:
Virtual Functions under Virtual Inheritance
Consider the following virtual base class derivation of Point3d from Point2d:
class Point2d {
public:
Point2d( float = 0.0, float = 0.0 );
virtual ~Point2d();
virtual void mumble();
virtual float z();
// ...
protected:
float _x, _y;
};
class Point3d : public virtual Point2d
public:
Point3d( float = 0.0, float = 0.0, float = 0.0 );
~Point3d();
float z();
protected:
float _z;
};
Although Point3d has a single leftmost base class—Point2d—the beginning of Point3d and Point2d is no longer
coincident (as they are under nonvirtual single inheritance).
在虚继承中Point3D对象的开始部分不是Point2d子对象