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


使用上述代碼,得到如下的結果:

內存分佈如下所示:

這裏需要注意的是,派生類中的內存分佈和基類中的內存分佈不一樣,虛函數表中的地址發生了明顯的變化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章