C++内存布局:深入立即C++内存布局下

我们继续完成内存布局的讲解。

这次需要讲解的内容如下:

基类不含虚函数,使用虚继承,派生类中含有虚函数

基类含有虚函数,使用虚继承,派生类中不含虚函数

基类含有虚函数,使用虚继承,派生类中含有虚函数

基类含有虚函数,使用虚继承,向下派生多次

基类含有虚函数,多继承



1.1 基类不含虚函数,使用虚继承,派生类中含有虚函数

先不讲具体的原理,也不描述具体的现象,直接看程序运行的效果

template<typename T>
class CPoint
{
public:
	CPoint()
	{
		_x = 0;
		_y = 0;
		_z = 0;
	}

	 void setX(T newX)
	{
		//std::cout << "CPoint setX" << std::endl;
		_x = newX;
	}
	 void setY(T newY)
	{
		_y = newY;
	}
    void setZ(T newZ = 0)
	{
		_z = newZ;
	}


	 T getX() const
	{
		return _x;
	}

	 T getY() const
	{
		return _y;
	}

	 T getZ() const
	{
		return _z;
	}

public:
	T _x;
	T _y;
	T _z;
};

template<typename T>
class CPoint2D :  virtual public CPoint<T>
{
public:
	CPoint2D()
	{
		_x = 0;
		_y = 0;
		_z = 0;
	}

	CPoint2D(T x, T y, T z = 0)
	{
		_x = x;
		_y = y;
		_z = z;
	}

	CPoint2D(const CPoint2D &point2D)
	{
		_x = point2D.getX();
		_y = point2D.getY();
		_z = point2D.getZ();
	}

	const CPoint2D& operator = (const CPoint2D& point2D)
	{
		if (this == &point2D)
			return *this;

		_x = point2D.getX();
		_y = point2D.getY();
		_z = point2D.getZ();
	}

	void operator +(const CPoint2D& point2D)
	{
		_x += point2D.getX();
		_y += point2D.getY();
		_z += point2D.getZ();
	}

	void operator -(const CPoint2D &point2D)
	{
		_x -= point2D.getX();
		_y -= point2D.getY();
		_z -= point2D.getZ();
	}

	virtual T getZ() const
	{
		std::cout << "CPoint2D:"<<sizeof(CPoint2D<T>::getZ()) << std::endl;
		return 0;
	}
	
	virtual void setZ(T newZ = 0)
	{
		//std::cout << "CPoint2D:" << sizeof(CPoint2D::setZ()) << std::endl;
		_z = 0;
	}
};

void main()
{
	CPoint<double> m_Point;

	CPoint2D<double> m_Point2D(0.0,0.0);
	//CPoint3D<double> m_Point3D;
	std::cout <<"CPoint:"<<	sizeof(m_Point) << std::endl;
	std::cout <<"CPoint2D:"<< sizeof(m_Point2D)<< std::endl;

	printf("&CPoint2D::_x = %d\n", &CPoint2D<double>::_x);
<span style="white-space:pre">	</span>printf("&CPoint2D::_y = %d\n", &CPoint2D<double>::_y);
<span style="white-space:pre">	</span>printf("&CPoint2D::_z = %d\n", &CPoint2D<double>::_z);
	std::cin.get();
}

程序运行的结果如下所示:


在VS中,内存分布如图所示


上述的内存布局中,完整了列出了每个类中的内存布局,我们的重点是在CPoint2D中,CPoint2D中位于内存起始位置的是基类的内存分布,包含有三个double型的成员变量,接着是一个虚函数表指针,该虚函数表是由于派生类中的虚函数所产生的,并不是由于虚继承所带来的。

printf("&CPoint2D::_x = %d\n", &CPoint2D<double>::_x);
printf("&CPoint2D::_y = %d\n", &CPoint2D<double>::_y);
printf("&CPoint2D::_z = %d\n", &CPoint2D<double>::_z);
这三行代码输出的是类成员变量在类中的偏移量,这一输出值也证明了类中的内存布局如上图所示的。


1.2基类含有虚函数,使用虚继承,派生类中不含虚函数

template<typename T>
class CPoint
{
public:
	CPoint()
	{
		_x = 0;
		_y = 0;
		_z = 0;
	}

	 void setX(T newX)
	{
		//std::cout << "CPoint setX" << std::endl;
		_x = newX;
	}
	 virtual void setY(T newY)
	{
		_y = newY;
	}
    virtual void setZ(T newZ = 0)
	{
		_z = newZ;
	}


	 T getX() const
	{
		return _x;
	}

	 virtual T getY() const
	{
		return _y;
	}

	 virtual T getZ() const
	{
		return _z;
	}

public:
	T _x;
	T _y;
	T _z;
};

template<typename T>
class CPoint2D :  virtual public CPoint<T>
{
public:
	CPoint2D()
	{
		_x = 0;
		_y = 0;
		_z = 0;
	}

	CPoint2D(T x, T y, T z = 0)
	{
		_x = x;
		_y = y;
		_z = z;
	}

	CPoint2D(const CPoint2D &point2D)
	{
		_x = point2D.getX();
		_y = point2D.getY();
		_z = point2D.getZ();
	}

	const CPoint2D& operator = (const CPoint2D& point2D)
	{
		if (this == &point2D)
			return *this;

		_x = point2D.getX();
		_y = point2D.getY();
		_z = point2D.getZ();
	}

	void operator +(const CPoint2D& point2D)
	{
		_x += point2D.getX();
		_y += point2D.getY();
		_z += point2D.getZ();
	}

	void operator -(const CPoint2D &point2D)
	{
		_x -= point2D.getX();
		_y -= point2D.getY();
		_z -= point2D.getZ();
	}

	T getZ() const
	{
		std::cout << "CPoint2D:"<<sizeof(CPoint2D<T>::getZ()) << std::endl;
		return 0;
	}
	
	void setZ(T newZ = 0)
	{
		//std::cout << "CPoint2D:" << sizeof(CPoint2D::setZ()) << std::endl;
		_z = 0;
	}
};

程序运行的结果如下图所示,具体的结果也不用详细多说,一目了然。




1.3基类含有虚函数,使用虚继承,派生类中含有虚函数

template<typename T>
class CPoint
{
public:
	CPoint()
	{
		_x = 0;
		_y = 0;
		_z = 0;
	}


	 void setX(T newX)
	{
		//std::cout << "CPoint setX" << std::endl;
		_x = newX;
	}
	 virtual void setY(T newY)
	{
		_y = newY;
	}
    virtual void setZ(T newZ = 0)
	{
		_z = newZ;
	}




	 T getX() const
	{
		return _x;
	}


	 virtual T getY() const
	{
		return _y;
	}


	 virtual T getZ() const
	{
		return _z;
	}


public:
	T _x;
	T _y;
	T _z;
};


template<typename T>
class CPoint2D :  virtual public CPoint<T>
{
public:
	CPoint2D()
	{
		_x = 0;
		_y = 0;
		_z = 0;
	}


	CPoint2D(T x, T y, T z = 0)
	{
		_x = x;
		_y = y;
		_z = z;
	}


	CPoint2D(const CPoint2D &point2D)
	{
		_x = point2D.getX();
		_y = point2D.getY();
		_z = point2D.getZ();
	}


	const CPoint2D& operator = (const CPoint2D& point2D)
	{
		if (this == &point2D)
			return *this;


		_x = point2D.getX();
		_y = point2D.getY();
		_z = point2D.getZ();
	}


	void operator +(const CPoint2D& point2D)
	{
		_x += point2D.getX();
		_y += point2D.getY();
		_z += point2D.getZ();
	}


	void operator -(const CPoint2D &point2D)
	{
		_x -= point2D.getX();
		_y -= point2D.getY();
		_z -= point2D.getZ();
	}


	virtual T getZ() const
	{
		std::cout << "CPoint2D:"<<sizeof(CPoint2D<T>::getZ()) << std::endl;
		return 0;
	}
	
	virtual void setZ(T newZ = 0)
	{
		//std::cout << "CPoint2D:" << sizeof(CPoint2D::setZ()) << std::endl;
		_z = 0;
	}
};


使用上述代码,得到如下的结果:

内存分布如下所示:

这里需要注意的是,派生类中的内存分布和基类中的内存分布不一样,虚函数表中的地址发生了明显的变化。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值