C++对象模型简介

为什么C++可以“自动完成”这么多事情,多态的底层实现是什么样子的,理解了C++的对象模型后,可以写出比较没有错误且比较有效的代码


目录

1、C与C++代码差异

 2、C++封装布局成本

3、C++对象模型

4、对象模型内部转换简介


1、C与C++代码差异

在C语言中,“数据”和“处理数据的函数”是分开声明的,像这样子:

typedef struct point3d
{
	float x;
	float y;
	float z; 
}Point3d;

 想要打印一个Point3d,可以直接定义一个这样的函数

void Point3d_print(const Point3d *pd)
{
	printf("(%f, %f, %f)",pd->x, pd->y, pd->z);
}

对特定点的坐标值,可以直接进行存取

Point3d pt;
pt.x = 0.0;

在C++语言中,“数据”和“处理数据的函数”是合并在一起的,像这样子。

class Point3d
{
public:
	Point3d(float x = 0.0,float y = 0.0,float z = 0.0)
		:_x(x),_y(y),_z(z){}
	float x() {return _x;}
	float y() {return _y;}
	float z() {return _z;}
	
	void x(float xval){_x=xval;}
private:
	float _x;
	float _y;
	float _z;
};

inline ostream &
operator <<(ostream &os,const Point3d &pt)
{
	os << "(" <<pt.x()<<","
		<<pt.y() <<","<<pt.z()<<")";
}

利用C++的继承特性,或是这样的代码

class Point
{
public:
	Point(float x = 0.0):_x(x){}
	float x(){return _x;}
	void x(float xval){_x=xval;}
	
protected:
	float _x;
};

class Point2d : public Point
{
public:
	Point2d(float x=0.0,float y=0.0):Point(x),_y(y){}
	
	float y(){return _y;}
	void y(float yval){_y=yval;}
	//...
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){}
	
	float z(){return _z;}
	void z(float zval){_z=zval;}
	//...
protected:
	float _z;
};

利用C++的模板特性,或是这样的代码

template <class type>
class Point3d
{
public:
	Point3d(type x=0.0, type y=0.0, type z=0.0)
		: _x(x),_y(y),_z(z){}
	
	type x(){return _x;}
	void x(type xval){_x = xval;}
	
	//...
private:
	type _x;
	type _y;
	type _z;
};

很显然,C和C++在程序风格上的差异巨大,那么从软件工程的角度看,C++有什么好处和坏处呢?C++的好处是:

1)封装,外部无法直接访问内部数据,有利于软件工程快速集成。

2)代码复用,继承和类提高代码开发效率,降低成本。C++的坏处在于并不精瘦和简洁,难理解(相对C而言)。

 2、C++封装布局成本

C++使用了class关键字对数据和函数进行了封装,那么封装后的成本是多少?有没有额外的内存增加,有没有额外的访存时间开销?答案是class Point3d并没有增加以上的成本,三个data member 直接内含在一个class object中,就像C 的struct一样。而member function 虽然在class中声明,但不会出现在object中。每一个non-inline member function 只会诞生一个函数实例。

你会看到C++的额外开销是由virtual 引起的,包括:

  • virtual function 机制,用以支持一个有效率的“执行期绑定”。
  • virtual base class 机制,用以支持“多次出现在继承体系中的base class,有一个单一而被共享的实例”。

3、C++对象模型

在C++中,有两种class data members: static 和nonstatic,以及三种class member functions: static、nonstatic和virtual。已知下面的class Point声明:

class Point
{
public:
	Point(float xval);
	virtual ~Point();
	
	float x() const;
	static int PointCount();
	
protected:
	virtual ostream&
		print(ostream &os)const;
		
	float _x;
	static int _point_count;
};

那么它的模型是什么样子呢?Nonstatic data members被配置于每一个class object之内,static data members则被存放在个别的class object之外。virtual function 则以两个步骤支持:

1)每个class 产生出一堆指向virtual functions的指针,放在表格之中。这个表格称为virtual table(vtabl)。

2)每个class object被安插一个指针,指向相关的virtual table。通常这个指针被称为vptr。vptr的setting和reset ting,都是由每一个class的constructor、destructor和copy assignment运算符完成。每一个class关联的type_info object(用来支持runtime type identification,RTTI)也由virtual table被指出来,通常放在表格的第一个slot中。

图1-1 C++对象模型

4、对象模型内部转换简介

对于以上C++对象模型,对于函数实现有什么影响呢?举个例子,例如class X的定义如下:

class X
{
public:
	X(const X & other){}
	virtual ~X(){}
	virtual void  foo(){}
};

那么对于一下的函数,内部可能转换成什么样子呢?

X foobar()
{
	X xx;
	X *px = new X;
	
	//foo()是一个virtual function
	xx.foo();
	px->foo();
	
	delete px;
	return xx;
};

可能转换成如下代码

//可能内部转换结果
//虚拟C++代码
void foobar(X &_result)
{
	//构造_result
	//_result 用来取代local xx
	_result.X::X();
	
	//扩展 X *px = new X;
	px = _new(sizeof(X));
	if( px != 0)
		px->X:X();
	
	//扩展xx.foo()但不能使用virtual 机制
	//以 _restult取代xx
	foo(&_result);
	
	//使用virtual 机制扩展px->foo()
	(*px->vtbl[2])(px);
	
	//扩展delete px;
	if(px != 0)
	{
		(*px->vtbl[1])(px);//destructor
		_delete(px);
	}
	
	//无须使用named return statement;
	//无须摧毁local object xx
	return;
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值