C++对象模型之四 成员函数笔记 (转)

C++对象模型之四 成员函数笔记 (转)[@more@] 

C++对象模型之四 成员函数笔记XML:namespace prefix = o ns = "urn:schemas-microsoft-com:Office:office" />

成员函数的调用方式

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

所以编译器内化成非成员函数,其步骤 1改写函数的原型以安插一个额外的参数到成员函数中,用以提供一个存取管道,使类对象得以调用该函数。 这个参数为 this 指针。

Point3d::Mangitude( Point3d *const this);

2 将每个对非静态数据成员的存取操作改为经由this指针来存取。

 {  return sqr( this->_x * this->_x+ this->_y * this->_y+ this->_z * this->_z);  }

3 将成员函数重新写成一个外部函数,对函数名称进行 mangling 处理。

 Extern mangitude __7Point3dFv ( regiester Piont3d *const this)

虚成员函数 register float mag = Magnitude();  è register float mag = ( *this->vptr[2]) (this);

1 编译器生成vptr指针;2 虚函数表中的索引值;3就是this 指针

静态成员函数 obj.Magnitude(); ptr->Magnitude(); 都会转化成 Magnitude__7Point3dsfv();

虚成员函数

如果类中有虚函数,就会有虚函数表指针(vptr),表格的地址,大小和内容都是编译掌握住了。

执行时要做的是在特定的虚函数表槽激活虚函数。虚函数包括:1 派生类改写基类的虚函数,2 继承基类的虚函数,3 纯虚函数。

Class Pont

{

 public:

  virtual ~Point();

  virtual Point& mult(float)=0;

  float x() const {return _x;}

  virtual float y() const { return 0;}

  virtual float x() const { return 0;}

protecetd:

  point (float x = 0.0);

  float _x;

};

ASPectratio="t" v:ext="edit">CSDN_Dev_Image_a%20href=2003-8-31933440.jpg">

 

当一个类派生自Point时,会发生什么?

1 可能它继承基类所声明的虚函数的函数实体,正确地说是该函数实体的地址会被拷贝到派生类的虚函数表相对应的槽中

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

3 可能它可以加入一个新的虚函数表,这时候虚函数表的尺寸会增大一个槽,而新的函数实体地址会被放进该槽中。

多重继承下得虚函数

 复杂度围绕在第二个及后继的基类身上,以及必须在执行时调整this指针

class Base1{

public: Base1();

virtual ~Base1();

virutal void speckclearly();

virutal Base1 *clone() const;

protected:  float data_Base1;

};

class Base2{

public: Base1();

virtual ~Base2();

virutal void mumble();

virutal Base1 *clone() const;

protected:  float data_Base2;

};

class Derived :public Base1,public Base2

{

  public:

  Derived();

  Virtual ~Derived();

 Virtual Derived *clone() const;

Protected :  float data_Derived;

};

Base2  *pbase2 = new derived;

è 调整:  Derived *temp = new Derived;  Base2 *pbase2 = temp ? temp + sizeof(Base1):0;

当第二个基类的指针调用派生类的虚函数时,必须在执行中完成调整。也就是offset

this+=sizeof(base1);

Derived::~Derived(this);

CSDN_Dev_Image_2003-8-31933442.jpg

 

CSDN_Dev_Image_2003-8-31933444.jpg

 

 

虚函数在虚继承下

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 );

~Point3d();

float z();

protected:  float _z;

};

由于Point2d和Point3d的对象不再相符,两者之间的转换也就需要调整this指针.

CSDN_Dev_Image_2003-8-31933446.jpg

 

 

 

 

 

 

CSDN_Dev_Image_2003-8-31933448.jpg

 

函数效率

 

优化

优化

内联成员

4.70

0.08

友元函数

6.13

4.43

静态成员

6.13

4.43

非静态成员

6.13

4.43

虚函数

6.90

4.76

虚函数多继承

7.06

4.90

虚函数虚继承

7.07

5.44

 

指向成员函数的指针

取个非静态成员函数的地址,如果它不是虚函数,则得到的是在内存中真正的地址。不过需要绑定在某个对象地址上。使用一个成员函数指针,如果并不用于虚函数,多重继承,虚继承等情况不会比一般的指针成本高。

 指向虚函数的指针

  float (Point:: *pmf) () = &Point::z;  //取虚函数的地址得到是在虚函数表的索引值

( * ptr->vptr[ (int) pmf ] ) (ptr);  //通过调用会被内部转化为一个编译时期的式子

区分PMF调用的是虚函数还是非虚函数方法:

( ( ( int ) pmf ) & ~127 ) ? (* pmf ) ( ptr ) : ( *ptrèvptr[ ( int) pmf ] ( ptr ) );

指向多重继承和虚继承的指针

采用结构体

struct _mptr

{

 int delta;  //表示this指针的offset

int  index;

union {

  ptrtofunc faddr;

int  v_offset;  //虚函数在虚函数表的索引

};

};

( ptr-> *pmf) (); 会变成 (pmf.index < 0 )? ( pmf.faddr ) (ptr ): ( ptr->vptr[ pmf.index ]( ptr ) );

 

指向成员函数指针的效率

 

未优化

优化

非成员函数指针

6.12

4.30

成员函数指针

6.38

4.30

多重继承非虚函数指针

6.32

4.30

虚继承非虚函数指针

6.84

4.70

虚函数指针

7.39

4.70

多重继承虚函数指针

8.72

5.90

虚继承虚函数指针

8.80

5.84

 

内联函数

一般而言处理内联函数有两个阶段

1 分析函数定义,以决定函数的内联的本资。如果判断其不可内联就会转化成静态函数。

2 内联函数的展开是在调用点上,这样会带来参数求值和临时对象管理。

形式参数

inline int min( int I,int j) { return  I

main()

{

  int minval ;

  int  val1=1024;

  int  val2=2048;

 minval = min (val1,val2);

 minval = min (1024,2048);

 minval = min (foo(),bar()+1);

}

第一调用的  minval =  val1

第二调用的  minval = 1024;

第三调用的  int t1; int t2; minval = (t1 =foo() ),(t2 = bar()+1) t1

在inline扩展时,每一个形式参数都会被实际参数取代。如果会导致对于实际参数多次求值就会引入临时对象。

局部变量

inline int min(int i,int j)

{

  int minval = i < j ? i : j ;

 return minval  ;

}

main()

{  int loval _var,minval;

  minval = min (val1,val2);

}

就会被扩展为:

{  int local _var, minval ;

  int__min_lv_minval;

  minval = (__min_lv_minval = val1 < val2 ? val1: val2), __min_lv_minval;

}

一般而言,内联函数中的每个局部变量都必须被放在函数调用的一个封闭区间中,拥有独一无二的名称。

如果内联函数以单一表达式扩展多次,那么每次都需要一组局部变量。以分离多个式子被扩展多次,那么只需要一组局部变量,就可以重复使用了。

 

 

   作者名:曾凡坤, 又名曾牧暗鲨,网名:大白鲨 2003-8-3

 


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10752043/viewspace-959339/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10752043/viewspace-959339/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值