分别打印栈、静态区、堆区、常量区变量地址
int i = 0;static int j = 1;int* p1 = new int;const char* p2 = "123456";printf("栈:%p\n", &i);printf("静态区:%p\n", &j);printf("堆区:%p\n", &p1);printf("常量区:%p\n", &p2);
构造基类shape,triangle类public继承自shape
class shape
{
public:virtual void draw() {}virtual void count() {}void ordinary_function() {}
};class triangle : public shape
{
public:triangle(int a, int b, int c): _a(a), _b(b), _c(c){}virtual void draw() {cout << "△" << endl;}virtual void count() {cout << _a + _b + _c << endl;}
private:int _a;int _b;int _c;
};void Test(shape& s)
{s.draw();s.count();
}
分别构造基类对象s和派生类对象t,使用shape类型的指针指向s
shape类型的对象指针指向s,如果对该指针此时解引用,得到的将是虚表的地址,对其进行打印即可,我们知道shape对象的大小应该是四个字节(vs2019编译环境下),这四个字节就指向了虚表,解引用的内容也就是虚表地址。
triangle类型的对象指针指向t,我们知道shape对象的大小应该是16个字节(vs2019编译环境下),因为其内部有三个内置类型成员变量,以及一个虚表,我们如果想让指针仅指向这前四个字节大小也就是指向虚表位置,可以将triangle类型对象的指针强转为 int* 类型的指针,对强转之后的指针进行解引用就可以得到以四个字节为单位的地址。(在多继承下可以查看其他虚表地址)
shape s; // 基类对象triangle t(1, 2, 3); // 派生类对象 Test(t);shape* p3 = &s;triangle* p4 = &t;printf("shape虚表指针:%p\n", *(int*)p3);printf("shape虚表指针:%p\n", *p3);printf("triangle虚表指针:%p\n", *(int*)p4);printf("虚函数地址: %p\n", &shape::draw);printf("普通函数地址: %p\n", &shape::ordinary_function);
通过对比,VS编译器下虚表、虚函数存在于常量区(代码段)。