深入探索c++对象模型(一、类对象所占用的空间)

临近过年,进程调度就先暂停,因为进程调度涉及的东西比较多,也不能都带回老家,所以过年这段时间准备卷《深入探索c++对象模型》。这本书越看越让人绝望,好难啊。所以就一边看一遍做笔记,分析,希望能看的懂。加油,哈哈哈。

1.1 空的类所占大小

从c转到c++,都比较喜欢做对比,特别是学习对象的时候,就喜欢比较struct和class了,所以这一次我们也来讨论一下struct数据占用的大小。

1.1.1 c语言中空的struct占用的大小

在写c语言的时候,我们经常使用struct,但是都没有去研究空的struct所占的大小,下面我们来看看

上代码:

#include <stdio.h>

struct A 
{
    //char a;
};


int main(int argc, char **argv)
{
    printf("sizeof(struct A) = %ld\n", sizeof(struct A));
    struct A a;
    printf("sizeof(a) = %ld &a = %p\n", sizeof(a), &a);
    *(char *)(&a) = 13;
    printf("*(char *)&a = %d\n", *(char *)(&a));

    struct A b;
    printf("sizeof(b) = %ld &b = %p\n", sizeof(b), &b);
    *(char *)(&b) = 1;
    printf("*(char *)&b = %d\n", *(char *)(&b));

    struct A c;
    printf("sizeof(c) = %ld &c = %p\n", sizeof(c), &c);
    *(char *)(&c) = 55;
    printf("*(char *)&c = %d\n", *(char *)(&c));

    return 0;
}

编译,运行:

sizeof(struct A) = 0
sizeof(a) = 0 &a = 0x7ffc10a16895
*(char *)&a = 13
sizeof(b) = 0 &b = 0x7ffc10a16896
*(char *)&b = 1
sizeof(c) = 0 &c = 0x7ffc10a16897
*(char *)&c = 55

差一点就被c语言的语法糖给骗了,sizeof可能做了处理,毕竟a,b,c都是实实在在的变量,并且也分配了地址,竟然分配了地址那就肯定有空间的吧,所以我就用指针指向这个空间,并且修改了值,编译输出发现真的是可以改变这个值,原来底层是这样的。

1.1.2 c++中空的struct占用大小

看了c语言的,我们也看看c++的如何:

#include <iostream>
#include <stdio.h>

using namespace std;

struct A 
{
    //char a;
};


int main(int argc, char **argv)
{

    cout << "sizeof(A) = " << sizeof(A) << endl;
    A a;   // c++中的struct是可以省略struct
    cout << "sizeof(a) = " << sizeof(a) << " &a = " << &a << endl;
    *reinterpret_cast<char *>(&a) = 45;
    printf("*reinterpret_cast<char *>(&a) = %d\n", *reinterpret_cast<char *>(&a));

    A b;
    cout << "sizeof(b) = " << sizeof(b) << " &b = " << &b << endl;
    *(char *)(&b) = 122;
    printf("*(char *)(&b) = %d\n", *(char *)(&b));

    A c;
    cout << "sizeof(c) = " << sizeof(c) << " &c = " << &c << endl;
    cout << "*(char *)&c = " << *(char *)(&c) << endl;

    return 0;
}

编译运行:

root@ubuntu:~/c++_mode/01# ./test_struct_cpp
sizeof(A) = 1
sizeof(a) = 1 &a = 0x7ffdb8cd3335
*reinterpret_cast<char *>(&a) = 45
sizeof(b) = 1 &b = 0x7ffdb8cd3336
*(char *)(&b) = 122
sizeof(c) = 1 &c = 0x7ffdb8cd3337
*(char *)&c = 
root@ubuntu:~/c++_mode/01# 

还是printf函数无敌啊,printf函数实现之后再解释把,意思就是把这块内存按指定格式输出,cout不支持这种格式,所以就没输出吧,应该是这样的。

这个sizeof的值也是1个字节,通过指针指向这个地址,并且修改里面的值,都是有效的,也符合我们的预期。

1.1.3 空的class所占大小

经过上面的两轮测试,猜测这个空的class也是占用一个字节,然后这个字节也是可以操作的,我们就来用代码来测试一波:

#include <iostream>
#include <stdio.h>

using namespace std;

class A
{

};

int main(int argc, char **argv)
{
    cout << "sizeof(A) = " << sizeof(A) << endl;
    A a;   // c++中的struct是可以省略struct
    cout << "sizeof(a) = " << sizeof(a) << " &a = " << &a << endl;
    *reinterpret_cast<char *>(&a) = 45;
    printf("*reinterpret_cast<char *>(&a) = %d\n", *reinterpret_cast<char *>(&a));

    A b;
    cout << "sizeof(b) = " << sizeof(b) << " &b = " << &b << endl;
    *(char *)(&b) = 122;
    printf("*(char *)(&b) = %d\n", *(char *)(&b));

    A c;
    cout << "sizeof(c) = " << sizeof(c) << " &c = " << &c << endl;
    cout << "*(char *)&c = " << *(char *)(&c) << endl;

    return 0;
}

我们来看看编译运行后的结果:

root@ubuntu:~/c++_mode/01# ./test_class
sizeof(A) = 1
sizeof(a) = 1 &a = 0x7ffe9c30a1e5
*reinterpret_cast<char *>(&a) = 45
sizeof(b) = 1 &b = 0x7ffe9c30a1e6
*(char *)(&b) = 122
sizeof(c) = 1 &c = 0x7ffe9c30a1e7
*(char *)&c = 
root@ubuntu:~/c++_mode/01# 

跟我们猜想的一样,哈哈哈。

这样面试的时候,碰到这个问题就可以大胆的说,空类大小是一个字节。

1.2 成员变量占的空间

上面介绍了空的类占用的大小,接下来我们就来看看在类中或结构体中定义成员变量所占的空间。

1.2.1 c语言结构体变量

#include <stdio.h>

struct A 
{
    char a;     // 4
    int b;      // 4
    float c;       // 8
    double d;       // 8
};


int main(int argc, char **argv)
{
    printf("sizeof(struct A) = %ld %ld %ld\n", sizeof(struct A), sizeof(int), sizeof(float));
    struct A a;
    printf("sizeof(a) = %ld &a = %p\n", sizeof(a), &a);
    printf("&a = %p, &b = %p, &c = %p &d = %p\n", &(a.a), &(a.b), &(a.c), &(a.d));

    
    struct A b;
    printf("sizeof(b) = %ld &b = %p\n", sizeof(b), &b);
    printf("&a = %p, &b = %p, &c = %p &d = %p\n", &(b.a), &(b.b), &(b.c), &(b.d));

    return 0;
}

编译运行:

root@ubuntu:~/c++_mode/01# ./test_struct
sizeof(struct A) = 24 4 4
sizeof(a) = 24 &a = 0x7ffdaa2ba8b0
&a = 0x7ffdaa2ba8b0, &b = 0x7ffdaa2ba8b4, &c = 0x7ffdaa2ba8b8 &d = 0x7ffdaa2ba8c0
sizeof(b) = 24 &b = 0x7ffdaa2ba8d0
&a = 0x7ffdaa2ba8d0, &b = 0x7ffdaa2ba8d4, &c = 0x7ffdaa2ba8d8 &d = 0x7ffdaa2ba8e0
root@ubuntu:~/c++_mode/01# 

24个字节,还是很符合的,有人问了,为啥不是17个字节,那是因为cpu为了提高访问速度,而做了内存对齐,我是64位的系统,所以是8字节对齐,这样也能保证一个int能在一个时钟周期就能读到变量的值。

因为内存对齐,会把char后面的3个字节补0,然后从第4个字节开始才是int b,这样b是可以一个时钟周期就能访问到,然后float被对齐成8个字节了,double还是原来的8个字节。

struct A b;也再次对齐,所以起始地址是0x7ffdaa2ba8d0。

这是因为在现在计算中,内存不是那么的紧缺了,所以编译器就会做一些适当的优化,来提高cpu的访问。

1.2.2 c++结构体变量

这个就不写了吧,跟c语言的一模一样,就把代码贴上来?凑凑字数,哈哈。

#include <iostream>
#include <stdio.h>

using namespace std;

struct A 
{
    char a;     // 4
    int b;      // 4
    float c;       // 8
    double d;       // 8
};


int main(int argc, char **argv)
{
    printf("sizeof(A) = %ld %ld %ld\n", sizeof(A), sizeof(int), sizeof(float));
    A a;
    printf("sizeof(a) = %ld &a = %p\n", sizeof(a), &a);
    printf("&a = %p, &b = %p, &c = %p &d = %p\n", &(a.a), &(a.b), &(a.c), &(a.d));

    
    A b;
    printf("sizeof(b) = %ld &b = %p\n", sizeof(b), &b);
    printf("&a = %p, &b = %p, &c = %p &d = %p\n", &(b.a), &(b.b), &(b.c), &(b.d));


    return 0;
}

代码都贴了,运行结果也贴出来吧。

root@ubuntu:~/c++_mode/01# ./test_struct_cpp
sizeof(A) = 24 4 4
sizeof(a) = 24 &a = 0x7ffd4a2b02a0
&a = 0x7ffd4a2b02a0, &b = 0x7ffd4a2b02a4, &c = 0x7ffd4a2b02a8 &d = 0x7ffd4a2b02b0
sizeof(b) = 24 &b = 0x7ffd4a2b02c0
&a = 0x7ffd4a2b02c0, &b = 0x7ffd4a2b02c4, &c = 0x7ffd4a2b02c8 &d = 0x7ffd4a2b02d0
root@ubuntu:~/c++_mode/01#

没什么好分析的。

1.2.3 class成员变量

其实class也是一样的,直接上代码吧。

#include <iostream>
#include <stdio.h>

using namespace std;

class A
{
public:
    char a;     // 4
    int b;      // 4
    float c;       // 8
    double d;       // 8
};

int main(int argc, char **argv)
{
    printf("sizeof(A) = %ld %ld %ld\n", sizeof(A), sizeof(int), sizeof(float));
    A a;
    printf("sizeof(a) = %ld &a = %p\n", sizeof(a), &a);
    printf("&a = %p, &b = %p, &c = %p &d = %p\n", &(a.a), &(a.b), &(a.c), &(a.d));

    
    A b;
    printf("sizeof(b) = %ld &b = %p\n", sizeof(b), &b);
    printf("&a = %p, &b = %p, &c = %p &d = %p\n", &(b.a), &(b.b), &(b.c), &(b.d));


    return 0;
}

一模一样的代码,肯定是在凑字数,水文。。。

运行结果(水也要水下去,没办法):

root@ubuntu:~/c++_mode/01# ./test_class
sizeof(A) = 24 4 4
sizeof(a) = 24 &a = 0x7ffef948b970
&a = 0x7ffef948b970, &b = 0x7ffef948b974, &c = 0x7ffef948b978 &d = 0x7ffef948b980
sizeof(b) = 24 &b = 0x7ffef948b990
&a = 0x7ffef948b990, &b = 0x7ffef948b994, &c = 0x7ffef948b998 &d = 0x7ffef948b9a0
root@ubuntu:~/c++_mode/01#

这个就不解释了。。。。。。。。。

1.3 静态变量占的空间

一看到静态变量占的空间,我就在想结构体中可以有static修饰的变量么?好像没有这个印象,那我们就来体验一波。

1.3.1 c语言结构体是否支持静态变量

root@ubuntu:~/c++_mode/01# gcc test_struct.c -o test_struct
test_struct.c:9:5: error: expected specifier-qualifier-list before ‘static’
     static int e;
     ^
root@ubuntu:~/c++_mode/01# 

恭喜大家,不支持。(少了不少字哈哈)

1.3.2 c++结构体静态变量

那c++结构体中能支持么?感觉是可以的,因为c++的strut跟class差别就只有权限了。那我们来看看:

#include <iostream>
#include <stdio.h>

using namespace std;

struct A 
{
    char a;     // 4
    int b;      // 4
    float c;       // 8
    double d;       // 8
    static int e;
};

int A::e = 0;    // 这个重点,需要初始化才能使用

int main(int argc, char **argv)
{
    printf("sizeof(A) = %ld %ld %ld\n", sizeof(A), sizeof(int), sizeof(float));
    A a;
    printf("sizeof(a) = %ld &a = %p\n", sizeof(a), &a);
    printf("&a = %p, &b = %p, &c = %p &d = %p &e = %p\n", &(a.a), &(a.b), &(a.c), &(a.d), &(A::e));

    
    A b;
    printf("sizeof(b) = %ld &b = %p\n", sizeof(b), &b);
    printf("&a = %p, &b = %p, &c = %p &d = %p &e = %p\n", &(b.a), &(b.b), &(b.c), &(b.d), &(A::e));


    return 0;
}

想不到c++的struct还真可以定义static成员变量,并且需要初始化后才能使用,不初始化是不能使用的,这个要记住。

编译运行:

root@ubuntu:~/c++_mode/01# ./test_struct_cpp
sizeof(A) = 24 4 4
sizeof(a) = 24 &a = 0x7ffeceac8ea0
&a = 0x7ffeceac8ea0, &b = 0x7ffeceac8ea4, &c = 0x7ffeceac8ea8 &d = 0x7ffeceac8eb0 &e = 0x60105c
sizeof(b) = 24 &b = 0x7ffeceac8ec0
&a = 0x7ffeceac8ec0, &b = 0x7ffeceac8ec4, &c = 0x7ffeceac8ec8 &d = 0x7ffeceac8ed0 &e = 0x60105c
root@ubuntu:~/c++_mode/01# 

发现结构体的大小并没有改变,还是24个字节,并且我们打印出来的值也不是在栈区,而是在数据区,0x60105c这地址就是数据区的部分,如果不知道的,可以看我之前的重学计算机的文章,所以这个静态变量是不算在对象空间内的。

那c++编译器是怎么把这个A::e这个变量名称存储起来的?

这个也可以看我的重学计算机里的符号表分析,其实c++编译器会把这个变量名加上修饰,下面是我反编译出来的结果:

68: 000000000060105c     4 OBJECT  GLOBAL DEFAULT   26 _ZN1A1eE

我是用g++来编译的,在gcc的基本c++名称修饰方法:

  1. 所有符号都以"_Z"开头。
  2. 对于在名称空间或在类里面,后面紧跟"N".
  3. 然后就是各个名称空间和类的名字,每个名字前是名字字符串长度。如:1A。长度为1,类名为A
  4. 最后以"E"结尾。
  5. 如果是函数的话,E后面会跟函数的参数列表。

所以这一串字符_ZN1A1eE就能解释的通了,学习真是一个网啊。

1.3.3 class的静态变量

class和struct其实是差不多的拉。这个就不写了,写太多也不好看,运行结果就跟1.3.2的一样。

符号保存也在1.3.2的一样,在c++中class跟struct真的区别不大。

1.4 成员函数占的空间

终于把成员变量讲完了,我们来看看成员函数。

1.4.1 c语言结构体不支持成员函数

毋庸置疑c语言结构体是不支持成员函数的,但是我们可以用函数指针来代替成员函数,这也是c实现面向对象的方法。

下面看代码:

#include <stdio.h>

struct A 
{
    char a;     // 4
    int b;      // 4
    float c;       // 8
    double d;       // 8
    //static int e;
    int (*func1)(int a);   // 8
    int (*func2)(int a);   // 8
};


int main(int argc, char **argv)
{
    printf("sizeof(struct A) = %ld %ld %ld\n", sizeof(struct A), sizeof(int), sizeof(float));
    struct A a;
    printf("sizeof(a) = %ld &a = %p\n", sizeof(a), &a);
    printf("&a = %p, &b = %p, &c = %p &d = %p\n", &(a.a), &(a.b), &(a.c), &(a.d));

    
    struct A b;
    printf("sizeof(b) = %ld &b = %p\n", sizeof(b), &b);
    printf("&a = %p, &b = %p, &c = %p &d = %p\n", &(b.a), &(b.b), &(b.c), &(b.d));

    return 0;
}

编译运行:

sizeof(struct A) = 40 4 4
sizeof(a) = 40 &a = 0x7ffecac8f830
&a = 0x7ffecac8f830, &b = 0x7ffecac8f834, &c = 0x7ffecac8f838 &d = 0x7ffecac8f840
sizeof(b) = 40 &b = 0x7ffecac8f860
&a = 0x7ffecac8f860, &b = 0x7ffecac8f864, &c = 0x7ffecac8f868 &d = 0x7ffecac8f870

大小40,因为我这是64位系统,指针的大小是8个字节,所以刚好是40个字节。

通过上面的运行,就明白这种方法的缺点,就是太占用类对象的空间了,如果结构体中的方法很多,那这个结构体的变量就很大,如果这个结构体申请很多个变量,那也会导致内存的消耗。

在《深入探索c++对象模型》里确实出现了一种简单的对象模型是这样的:

在这里插入图片描述

就因为这个简单所以叫简单对象模型,哈哈哈。

1.4.2 c++结构体成员函数

c++的struct中的结构体跟类的是一样的,都可以支持成员函数。

#include <iostream>
#include <stdio.h>

using namespace std;

struct A 
{
    char a;     // 4
    int b;      // 4
    float c;       // 8
    double d;       // 8
    static int e;
    int fun1(int a);
    int fun2(int b);
};

int A::e = 0;

int A::fun1(int a)
{
    return a;
}

int A::fun2(int b)
{
    return b;
}

int main(int argc, char **argv)
{
    printf("sizeof(A) = %ld %ld %ld\n", sizeof(A), sizeof(int), sizeof(float));
    A a;
    printf("sizeof(a) = %ld &a = %p\n", sizeof(a), &a);
    printf("&a = %p, &b = %p, &c = %p &d = %p &e = %p\n", &(a.a), &(a.b), &(a.c), &(a.d), &(A::e));
    printf("func addr : fun1=%d func2=%d\n", a.fun1(1), a.fun2(2));

    
    A b;
    printf("sizeof(b) = %ld &b = %p\n", sizeof(b), &b);
    printf("&a = %p, &b = %p, &c = %p &d = %p &e = %p\n", &(b.a), &(b.b), &(b.c), &(b.d), &(A::e));
    //printf("func addr : fun1=%p func2=%p\n", b.fun1, b.fun2);

    return 0;
}

我们看一下编译运行的结果:

root@ubuntu:~/c++_mode/01# ./test_struct_cpp
sizeof(A) = 24 4 4
sizeof(a) = 24 &a = 0x7ffe50ceee70
&a = 0x7ffe50ceee70, &b = 0x7ffe50ceee74, &c = 0x7ffe50ceee78 &d = 0x7ffe50ceee80 &e = 0x60105c
func addr : fun1=1 func2=2
sizeof(b) = 24 &b = 0x7ffe50ceee90
&a = 0x7ffe50ceee90, &b = 0x7ffe50ceee94, &c = 0x7ffe50ceee98 &d = 0x7ffe50ceeea0 &e = 0x60105c
root@ubuntu:~/c++_mode/01# 

大小也是24,说明成员函数也不占用对象的空间,本来想直接打印成员函数地址,发现打印不了,怎么办?

勇气牛牛,不怕困难。

用gdb打印:

<A::fun1(int)>
(gdb) p a.fun1
$1 = {int (A * const, int)} 0x400776 <A::fun1(int)>
(gdb) p a.fun2
$2 = {int (A * const, int)} 0x400786 <A::fun2(int)>
(gdb) p b.fun1
$3 = {int (A * const, int)} 0x400776 <A::fun1(int)>
(gdb) p b.fun2
$4 = {int (A * const, int)} 0x400786 <A::fun2(int)>

发现不管那个对象调用fun1,地址都是一样的,并且这个地址是存储在代码区的,这种对象模型设计的就很节省内存。

接下来我们反编译看看,函数符号是怎么修饰的:

    70: 0000000000400776    16 FUNC    GLOBAL DEFAULT   14 _ZN1A4fun1Ei
    71: 0000000000400786    16 FUNC    GLOBAL DEFAULT   14 _ZN1A4fun2Ei

跟我们上面分析的是一样的,哟西哟西。

1.4.3 class成员函数

这个也不分析了,跟1.4.2是一样的,不信可以自己分析分析。

1.5 静态函数占的空间

竟然静态成员变量都不在类对象的空间里,那静态函数应该更不在类对象的空间里了,c语言就不分析了,反正也不支持,下面我们来分析分析:

#include <iostream>
#include <stdio.h>

using namespace std;

class A
{
public:
    char a;     // 4
    int b;      // 4
    float c;       // 8
    double d;       // 8
    static int e;
    int fun1(int a);
    int fun2(int b);
    static int sfun1(int a);
    static int sfun2(int a);
};

int A::e = 0;

int A::fun1(int a)
{
    return a;
}

int A::fun2(int b)
{
    return b;
}

int A::sfun1(int a)
{
    return a;
}

int A::sfun2(int b)
{
    return b;
}

int main(int argc, char **argv)
{
    printf("sizeof(A) = %ld %ld %ld\n", sizeof(A), sizeof(int), sizeof(float));
    A a;
    printf("sizeof(a) = %ld &a = %p\n", sizeof(a), &a);
    printf("&a = %p, &b = %p, &c = %p &d = %p &e = %p\n", &(a.a), &(a.b), &(a.c), &(a.d), &(A::e));
     printf("func addr : sfun1=%d sfunc2=%d\n", A::sfun1, A::sfun2);
    
    A b;
    printf("sizeof(b) = %ld &b = %p\n", sizeof(b), &b);
    printf("&a = %p, &b = %p, &c = %p &d = %p &e = %p\n", &(b.a), &(b.b), &(b.c), &(b.d), &(A::e));


    return 0;
}

编译运行:

root@ubuntu:~/c++_mode/01# ./test_class
sizeof(A) = 24 4 4
sizeof(a) = 24 &a = 0x7ffe32a18ae0
&a = 0x7ffe32a18ae0, &b = 0x7ffe32a18ae4, &c = 0x7ffe32a18ae8 &d = 0x7ffe32a18af0 &e = 0x60105c
func addr : sfun1=4196246 sfunc2=4196258
sizeof(b) = 24 &b = 0x7ffe32a18b00
&a = 0x7ffe32a18b00, &b = 0x7ffe32a18b04, &c = 0x7ffe32a18b08 &d = 0x7ffe32a18b10 &e = 0x60105c
root@ubuntu:~/c++_mode/01# 

果然也不占类对象的空间,并且也是存储在代码区中的:

76: 0000000000400796    12 FUNC    GLOBAL DEFAULT   14 _ZN1A5sfun1Ei

符号存储也是跟我们之前的一样。

c++的struct就不测试了。

1.6 虚函数占的空间

最后一个知识点,就是虚函数,在c++的类中是直接虚函数的,虚函数的作用主要是在多态上,现在不是详细分析的时候,反正看这个文章的,对c++都比较熟了,我们就直接来看看虚函数占多少个字节:

#include <iostream>
#include <stdio.h>

using namespace std;

class A
{
public:
    char a;     // 4
    int b;      // 4
    float c;       // 8
    double d;       // 8
    static int e;
    int fun1(int a);
    int fun2(int b);
    static int sfun1(int a);
    static int sfun2(int a);

    virtual int vfun1(int a);  // 8
    virtual int vfun2(int b);
};

int A::e = 0;

int A::fun1(int a)
{
    return a;
}

int A::fun2(int b)
{
    return b;
}

int A::sfun1(int a)
{
    return a;
}

int A::sfun2(int b)
{
    return b;
}


int A::vfun1(int a)
{
    return a;
}

int A::vfun2(int b)
{
    return b;
}


int main(int argc, char **argv)
{
    printf("sizeof(A) = %ld %ld %ld\n", sizeof(A), sizeof(int), sizeof(float));
    A a;
    printf("sizeof(a) = %ld &a = %p\n", sizeof(a), &a);
    printf("&a = %p, &b = %p, &c = %p &d = %p &e = %p\n", &(a.a), &(a.b), &(a.c), &(a.d), &(A::e));
     printf("func addr : sfun1=%d sfunc2=%d\n", A::sfun1, A::sfun2);
    
    A b;
    printf("sizeof(b) = %ld &b = %p\n", sizeof(b), &b);
    printf("&a = %p, &b = %p, &c = %p &d = %p &e = %p\n", &(b.a), &(b.b), &(b.c), &(b.d), &(A::e));


    return 0;
}

编译运行:

root@ubuntu:~/c++_mode/01# ./test_class
sizeof(A) = 32 4 4
sizeof(a) = 32 &a = 0x7fff9ffe9b20
&a = 0x7fff9ffe9b28, &b = 0x7fff9ffe9b2c, &c = 0x7fff9ffe9b30 &d = 0x7fff9ffe9b38 &e = 0x6010b4
func addr : sfun1=4196358 sfunc2=4196370
sizeof(b) = 32 &b = 0x7fff9ffe9b40
&a = 0x7fff9ffe9b48, &b = 0x7fff9ffe9b4c, &c = 0x7fff9ffe9b50 &d = 0x7fff9ffe9b58 &e = 0x6010b4
root@ubuntu:~/c++_mode/01# 

增加两个虚函数,大小比之前大了8个字节,刚好我是64位操作系统,刚好就是一个指针的大小,这个指针指向虚函数表的指针。

虚函数表的知识我们后面再解释把。

1.7 总结

最后引用一下,《深入探索c++对象模型》中的c++对象模型的图:

在这里插入图片描述

这个图就很好的总结了我们今天所说的内容:

  1. 成员变量在类对象里
  2. 成员函数不在类对象里,在代码段
  3. 静态成员变量也不在类对象里,在数据段
  4. 静态函数也不在类对象里,在代码段
  5. 如果类中有虚函数,就会产生一个指向虚函数表的指针。

最后,今天也是除夕,也祝大家新年快乐,明年继续卷,今年暂时不要卷了,好好过年,哈哈哈。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值