描述:
#define offsetofclass(base, derived) ((DWORD)(static_cast<base*>((derived*)_ATL_PACKING))-_ATL_PACKING)
是什么意思?
#define _ATL_PACKING 8
主要是下面这个
static_cast<base*>((derived*)_ATL_PACKING)
解决方案1:
这个宏变量返回drive的基类的虚指针的相对位移,让我们看下面一个例子。
#include <windows.h>
#include <iostream>
using namespace std;
class Base1 {
public:
virtual void f() { }
};
class Base2 {
public:
virtual void f() { }
};
class Base3 {
public:
virtual void f() { }
};
class Drive : public Base1, public Base2, public Base3 {
};
#define _ATL_PACKING 8
#define offsetofclass(base, derived)
((DWORD)(static_cast<base*>((derived*)_ATL_PACKING))-_ATL_PACKING)
int main() {
cout << offsetofclass(Base1, Drive) << endl;
cout << offsetofclass(Base2, Drive) << endl;
cout << offsetofclass(Base3, Drive) << endl;
return 0;
}
类drive的内存分配如下
程序输出结果:
0
4
8
程序输出说明这个宏的返回值是其所指定的基类的虚指针的相对位置,在Don Box所写的《Essential COM》一书中,用了一个简单的宏来完成这些工作。我们把程序作一个小小的改动来展示一下Box的宏
#include <windows.h>
#include <iostream>
using namespace std;
class Base1 {
public:
virtual void f() { }
};
class Base2 {
public:
virtual void f() { }
};
class Base3 {
public:
virtual void f() { }
};
class Drive : public Base1, public Base2, public Base3 {
};
#define BASE_OFFSET(ClassName, BaseName)
(DWORD(static_cast<BaseName*>(reinterpret_cast<ClassName*>
(0x10000000))) - 0x10000000)
int main() {
cout << BASE_OFFSET(Drive, Base1) << endl;
cout << BASE_OFFSET(Drive, Base2) << endl;
cout << BASE_OFFSET(Drive, Base3) << endl;
return 0;
}
程序的输出结果和原先的程序一样。
让我们来用这些宏作一些练习,实际上我们是通过取得这些虚函数的相对位移来调用这些虚函数
#include <windows.h>
#include <iostream>
using namespace std;
class Base1 {
public:
virtual void f() { cout << "Base1::f()" << endl; }
};
class Base2 {
public:
virtual void f() { cout << "Base2::f()" << endl; }
};
class Base3 {
public:
virtual void f() { cout << "Base3::f()" << endl; }
};
class Drive : public Base1, public Base2, public Base3 {
};
#define _ATL_PACKING 8
#define offsetofclass(base, derived)
((DWORD)(static_cast<base*>((derived*)_ATL_PACKING))-_ATL_PACKING)
int main() {
Drive d;
void* pVoid = NULL;
// call function of Base1
pVoid = (char*)&d + offs
算两个指针之间的偏移量。
因为一个类的所有对象的内存布局都是一样的,指针在内存中也只不过是一个数值,所以用8来代替与0xABCDFFF0是一样的。
那一句话相当于类型转化。就是要把指针从派生类的内存开始处移到基类的开始处,从而才能算出派生类与基类之间的内存偏移量。