我們繼續完成內存佈局的講解。
這次需要講解的內容如下:
基類不含虛函數,使用虛繼承,派生類中含有虛函數
基類含有虛函數,使用虛繼承,派生類中不含虛函數
基類含有虛函數,使用虛繼承,派生類中含有虛函數
基類含有虛函數,使用虛繼承,向下派生多次
基類含有虛函數,多繼承
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;
}
};
內存分佈如下所示:
這裏需要注意的是,派生類中的內存分佈和基類中的內存分佈不一樣,虛函數表中的地址發生了明顯的變化。