第四章


C++支持三种类型的member function:static,nostatic,virtual,每一种类型被调用的方式各不相同。

4.1 member的各种调用方式


1:非静态成员函数:

c++设计的准则之一是nostatic member function 和nomember function的调用效率一样 也就是

float magnitude3d(const Point3d *_this){……};

float Point3d::magnitude3d( ) const { ...} 有相同的效率

实际上 member function 被内化为nomember function的形式,其步骤为:

1):改写函数的函数原型,以安插一个额外的参数到member function中 即为 this 指针,Point3d Point3d:: magnitude3d(Point3d  * const this)如果member functon

是const的 则为Point3d Point3d:: magnitude3d(cosnt Point3d  *cosnt this)(*this所指向的对象的内容不能被更改)

2):转换后对每一个nostatic data member的存取操作由this指针来完成

3):将member function重新写成一个外部函数,对函数名“mangling”处理,使其在程序中名字独一无二, 例如:extern magnitude__7Point3dFv(
register Point3d *const this );

经过以上步骤 该函数被转换好,调用时有:

obj.magnitude();

magnitude__7Point3dFv( &obj );

ptr->magnitude();

magnitude__7Point3dFv( ptr );

name mangling处理

一般来说 编译器会把 member的名称加上class的名称,以形成独一无二的命名

2:virtual member function

如果成员函数是虚函数 则ptr-> normalize()(虚函数)转换为 ( * ptr->vptr[ 1 ])( ptr ); vptr:编译器所产生的指针,1为vpt的slot值,ptr表示this指针

obj.normalize();  ( * obj.vptr[ 1 ])( &obj );

3:static mermber function

obj.normalize();

ptr-> normalize()

如果调用的是静态成员函数 会转化为一般的nomember 函数调用 像这样:

// obj.normalize();
normalize__7Point3dSFv();
// ptr->normalize();
normalize__7Point3dSFv();

static member function的主要特性是它没有this指针,所以它有以下特性

1):它不能直接存取其class中的nonstatic members

2):它不能被声明为const,volatile,或者virtual。

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

一个static member function 会被提出class声明之外,并给予一个经过“mangled”的适当的名称 例如

unsigned int
object_count__5Point3dSFv()
{
return _object_count__5Point3d;
}

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

4.2 虚拟成员函数

为了支持virtual function机制,必须首先能够对多态对象有某种形式的“执行期类型判断法(runtime type resloution)”

例如 ptr->z():z为虚函数

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

例如:

Point *ptr;

ptr = new Point3d;

ptr的多态主要扮演一个输送机制的角色,经由他我们可以在程序的任何地方访问public derived类型,这种形式是在编译期间完成的是消极的(passive)的。但virtual bass class 除外。??????????????

调用ptr->z();

z是一个virtual function 什么样的信息才能让我们在执行期调用正确的z()实体

1)ptr 的真实类型  ----------------------在每一个class object身上增加两个members 1个字符串标class的类型(?????),一个指针 指向virtual function的表格

2)z实体的位置

为了找到表格 class被安插上一个指针指向该表格,为了找到函数的地址,每个virtual function 被指派一个表格索引值

一个class只会有一个virtual table(????????)

表中包括:1class所定义的实体,2继承自base class的函数实体(没有被改写),3一个pure_virtual_call()函数实体,它既扮演pure virtual function 的空间保卫角色

也可以当做执行期的异常处理函数(????????)

图示:


class Point {
public:
	virtual ~Point();
	virtual Point& mult( float ) = 0;
	// ... other operations ...
	float x() const { return _x; }
	virtual float y() const { return 0; }
	virtual float z() const { return 0; }
	// ...
	protected:
	Point( float x = 0.0 );
	float _x;
};

class Point2d : public Point {
	public:
		Point2d( float x = 0.0, float y = 0.0 ): 
		Point( x ), _y( y ) {}
		~Point2d();
		// overridden base class virtual functions
		Point2d& mult( float );
		float y() const { return _y; }
		// ... other operations ...
		protected:
		float _y;
};

class Point3d: public Point2d {
public:
	Point3d( float x = 0.0,
	float y = 0.0, float z = 0.0 )
	: Point2d( x, y ), _z( z ) {}
	~Point3d();
	// overridden base class virtual functions
	Point3d& mult( float );
	float z() const { return _z; }
	// ... other operations ...
	protected:
	float _z;
};

以上三个单一继承的virtual table布局 如下:


1:继承base class的所声明的virtual function的函数实体,会被拷贝到derived class的virtual table 相对应的slot中

2:它可以使用自己的函数实体,这表示它自己的函数实体的地址必须放在对应的slot中

3:它可以增加一个新的virtual function 这时候virtual table 的尺寸会增大



posted @ 2011-11-24 00:14  foreverlearn  阅读(151)  评论(0)    收藏  举报