程序6.
#include <iostream> using namespace std;
class CPoint { public: int m_ix; int m_iy; virtual ~CPoint() { } // 译注:原文此处有分号,我将其去掉,下皆同 };
int main() { CPoint objPoint; cout << "Size of Class = " << sizeof(objPoint) << endl; cout << "Address of Class = " << &objPoint << endl; return 0; } |
程序的输出为:
Size of Class = 12 Address of Class = 0012FF68 |
这些程序的输出表明,当你向类中添加了虚函数之后,那么它的尺寸就会增加一个int的大小。在Visual C++(www.cppentry.com)中也就是增加4个字节。这就意味着这个类中有三个整数大小的位置,一个是x,一个是y,另一个是处理虚函数之用的虚函数表指针。首先,让我们来看看这个新的位置,也就是这个位于对象首部(或末尾)的虚函数表指针。要这么做的话,我们需要直接存取对象所占用的内存。我们可以使用神奇的指针技术,即用一个指向int的指针来存储一个对象的地址。
程序7.
#include <iostream> using namespace std;
class CPoint { public: int m_ix; int m_iy; CPoint(const int p_ix = 0, const int p_iy = 0) : m_ix(p_ix), m_iy(p_iy) { } int getX() const { return m_ix; } int getY() const { return m_iy; } virtual ~CPoint() { } };
int main() { CPoint objPoint(5, 10);
int* pInt = (int*)&objPoint; *(pInt+0) = 100; // 企图改变x的值 *(pInt+1) = 200; // 企图改变y的值
cout << "X = " << objPoint.getX() << endl; cout << "Y = " << objPoint.getY() << endl;
return 0; } |
这个程序中最重要的东西是:
int* pInt = (int*)&objPoint; *(pInt+0) = 100; // 企图改变x的值 *(pInt+1) = 200; // 企图改变y的值 |
其中,我们在把对象的地址存入一个整型指针之后,就可以把这个对象看作一个整型的指针了。程序的输出为:
当然,这并不是我们想要的结果,它表明200存储在了m_ix数据成员的位置。这就意味着m_ix,也就是第一个成员变量,是起始于内存中第二个位置的,而不是第一个。换句话说,第一个成员是虚函数表指针,其它的才是对象的数据成员。那么,只需要修改以下的两行:
int* pInt = (int*)&objPoint; *(pInt+1) = 100; // 企图改变x的值 *(pInt+2) = 200; // 企图改变y的值 |
这样我们就会获得想要的结果了,以下为完整程序:
程序8.
#include <iostream> using namespace std;
class CPoint { public: int m_ix; int m_iy; CPoint(const int p_ix = 0, const int p_iy = 0) : m_ix(p_ix), m_iy(p_iy) { } int getX() const { return m_ix; } int getY() const { return m_iy; } virtual ~CPoint() { } };
int main() { CPoint objPoint(5, 10);
int* pInt = (int*)&objPoint; *(pInt+1) = 100; // 企图改变x的值 *(pInt+2) = 200; // 企图改变y的值
cout << "X = " << objPoint.getX() << endl; cout << "Y = " << objPoint.getY() << endl;
return 0; } |
并且,程序的输出为:
下图清楚地示范了当我们向类中添加了虚函数之后,虚函数表指针就会被添加在内存结构中的第一个位置。
现在问题出现了:虚函数表指针中到底存储了什么?那么看看下面的程序:
|