实验环境
Ubuntu 18.04 64-bit Gcc-7.3.0 G++-7.3.0,编译使用-m32选项启用32位环境
实验步骤
1、不含有虚函数的基类,代码如下:
#include <iostream>
class Base {
public:
Base(int val) : i(val) {}
private:
int i;
};
int main() {
Base b(1000);
std::cout << sizeof b << std::endl;
}
运行结果:
kevin@kvm:~/study/temp$ g++ -g test.cc -m32
kevin@kvm:~/study/temp$ ./a.out
4
结论:在不含有虚函数的情况下,Base类型实例的大小就是Base类成员变量的大小。
2、给基类添加虚函数,代码如下:
#include <iostream>
class Base {
public:
Base(int val) : i(val) {}
void print() { std::cout << "Base::print()" << std::endl; }
virtual int v_print_1() { std::cout << "Base::v_print_1()" << std::endl; }
virtual int v_print_2() { std::cout << "Base::v_print_2()" << std::endl; }
virtual ~Base() {};
private:
int i;
};
int main() {
Base b(1000);
std::cout << sizeof b << std::endl;
std::cout << "Content of internal storage : " << *((int *)&b + 1) << std::endl;
}
运行结果:
kevin@kvm:~/study/temp$ g++ -g test.cc -m32
kevin@kvm:~/study/temp$ ./a.out
8
Content of internal storage : 1000
结论:当基类本身定义了虚函数的时候(或继承的父类有虚函数),为了继承多态机制,编译器将为该类添加一个虚函数指针(__vfptr),虚函数指针指向虚函数表,虚函数表是一个指向虚函数的指针的数组(因此虚函数指针的类型为void ** __vfptr)。虚函数指针一般都放在对象内存布局的第一个位置上,这是为了保证在多层继承或多重继承的情况下能以最高效率取到虚函数表。同时我们发现,虽然Base类的数据成员 i 是 private的,我们也能够通过对象的地址得到其保存的值!
3、接下来,我们为Base类添加静态成员(static成员,包括静态成员变量和静态成员函数),代码如下:
#include <iostream>
typedef void (*Func)(void);
class Base {
public:
Base(int val) : i(val) {}
void print() { std::cout << "Base::print()" << std::endl; }
virtual int v_print() { std::cout << "Base::v_print()" << std::endl; }
virtual int v_print_2() { std::cout << "Base::v_print_2()" << std::endl; }
static int getj() { return j; }
virtual ~Base() {};
private:
int i;
static int j;
};
int Base::j;
int main() {
Base b(1000);
std::cout << "sizeof(b) = " << sizeof b << std::endl;
std::cout << "Content of internal storage = " << *((int *)&b + 1) << std::endl;
}
运行结果:
kevin@kvm:~/study/temp$ g++ -g test.cc -m32
kevin@kvm:~/study/temp$ ./a.out
sizeof(b) = 8
Content of internal storage = 1000
结论:我们看到,静态成员并不影响Base类实例的大小!