public:
int x;
int y;
void Foo();
void Bar(int newX, int newY);
virtual void VFoo();
static void SFoo();
static void SBar(int newX, int newY);
static int sx;
static int sy; }; 对于上面列出的这个类MyClass,C++编译器多数会以如下的方式进行编译:
现在我们再来看一下为什么编译器需要头文件和符号地址就可以编译链接一个使用MyClass的程序了。 首先,由于编译器需要在编译期就知道类的内存布局,以保证可以生成正确的开辟内存的代码,及那些 sizeof(MyClass)的值。有了头文件,编译器就知道,一个MyClass占用12字节的内存空间(见上图,两个整数和一 个指针)。 其次,在调用MyClass的成员函数、静态函数时,链接器需要知道这些函数的入口地址,如果无法提供入口地址, 链接器就会报错。 最后,在引用MyClass的静态数据成员时,实际上与引用一个外部全局对象一样,链接器需要知道这些变量的地址。 如果无法提供这些变量的地址,链接器也会报错。 可以看出: 1. 编译期:必须要提供的是类的头文件,以使编译器可以得知类实例的尺寸和内存布局。 2. 链接期:必须要提供的是程序中引用过的,类的成员函数、静态函数、静态数据成员的地址,以使链接器可以正确的生成最终程序。 到这里,我们可以猜到,实际上,导出一个类,编译器实际上只需要将这个类中的:成员函数、静态函数、静态数 据成员当成普通的函数、全局变量导出即可。也就是说,我们实际上没有“导出一个类”,而是把这个类中需要被 引用的“有定义的实体”的入口地址像普通函数和变量那样正常导出即可。由于里面的纯虚函数VBar没有 定义,所以不会被导出。