我们继续完成内存布局的讲解。
这次需要讲解的内容如下:
基类不含虚函数,使用虚继承,派生类中含有虚函数
基类含有虚函数,使用虚继承,派生类中不含虚函数
基类含有虚函数,使用虚继承,派生类中含有虚函数
基类含有虚函数,使用虚继承,向下派生多次
基类含有虚函数,多继承
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;
}
};
内存分布如下所示:
这里需要注意的是,派生类中的内存分布和基类中的内存分布不一样,虚函数表中的地址发生了明显的变化。