C++中空类、包含非静态成员类、包含静态成员类与包含虚函数类的sizeof字节计算与虚函数表指针介绍

文章详细介绍了C++中不同类型的类(如空类、包含成员变量和函数的类、含有静态成员和虚函数的类等)在内存中的表现,包括sizeof运算符的运用,以及类的字节大小如何受成员变量、静态成员、虚函数等因素影响。还讨论了继承、多重继承下虚函数表的处理方式,并提供了相应的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1、空类

2、包含非静态成员变量类

3、包含静态成员变量类

4、包含普通成员函数类

5、包含虚函数类

6、继承虚函数类

7、多重继承类

8、虚函数表

9、菱形继承


sizeof 是一个关键字,它是一个编译时运算符,用于判断变量或数据类型的字节大小。

sizeof 运算符可用于获取类、结构、共用体和其他用户自定义数据类型的大小。

使用 sizeof 的语法:sizeof (data type)

1、空类

      空类指没有成员和函数的类,编译器为了区别不同的空类实例对象,为空类内部默认增加了一个字节地址用于区分。所以sizeof空类的大小为1个字节。

2、包含非静态成员变量类

        类的大小是每个成员变量的占用内存的大小。 需要注意:有字节对齐规则:跟类中的成员变量类型最长的那个字节对对齐。   所以,为了节省空间,写类成员变量时,最小字节的写在前面。

关于字节对齐的介绍见链接

一文轻松理解内存对齐 (qq.com)

3、包含静态成员变量类

     静态成员变量定义时就以及在全局/静态存储区分配了内存,不属于类对象。非其静态成员变量的内存是属于类对象的,每个类对象都会复制一份内存。 静态成员变量只有一份,生存周期属于整个程序,所以不占用内对象的空间,字节大小为1。
 

4、包含普通成员函数类

成员函数的不占用内存大小,大小和空类一样。

5、包含虚函数类

     有虚函数的成员,类内部会有一个虚函数表指针vptr,vptr指向需函数表vtable,虚函数表中存放的是虚函数的地址。C++的虚函数机制跟C语言的函数指针(回调函数)类似。

虚函数表可参考链接:

C++继承和多态核心重点知识刨析,一文必拿下_c++继承与多态_小杰312的博客-优快云博客

 C语言回调函数可参考链接:

C 函数指针与回调函数 | 菜鸟教程 (runoob.com)

6、继承虚函数类

      只要基类有虚函数,子类不论实现或没实现,都有虚函数表子类不会和父类共用一个虚函数表,每个类都会有一个虚函数表。

关于虚函数表可参考:

父类与子类会共用一个虚函数表吗?_父类和子类共用一个虚表_lann*的博客-优快云博客

 c++ 子类没有虚函数,但是父类有虚函数,子类会新建虚表吗?_悠哉日常的博客-优快云博客

7、多重继承类

多重继承时,子类会继承两个基类的虚函数指针,分别指向虚函数表。子类与父类的同名函数,父类是虚函数,子类也是虚函数,子类的同名函数会覆盖父类的同名函数。

关于多重继承虚函数表可参考:

多重继承虚函数表分析_多层继承 虚函数表_Last-Week的博客-优快云博客

C++多态虚函数表详解(多重继承、多继承情况)_一个类有几个虚函数表_青城山小和尚的博客-优快云博客

8、虚函数表

虚函数表可参考:

C++虚函数与虚表 - 知乎 (zhihu.com)

demo代码如下:

#include <iostream>

using namespace std;

/*
 * 1、空类
 */
class A
{

};

struct StuA
{

};


/*
 * 2、类的非静态成员变量
 */

class B
{
public:
    int m_a;
    int m_b;
};
class B1
{
public:
    long  m_a;
    char  m_b;
    int   m_c;
    char  m_d;
};
class B2
{
public:
    char   m_a;
    char   m_b;
    int    m_c;
    long   m_d;
};

/*
 * 3、静态成员变量
 *
 */
class C
{
public:
    static int m_a;
};
int C::m_a = 0;

/*
 * 4、成员函数
 */
class D
{
public:
    D(){};
    ~D(){};
    void func(){};
};

/*
 * 5、虚拟成员函数
 */
class E
{
public:
    virtual void func(){};
};

/*
 * 6、继承虚拟员函数
 */
class F
{
public:
    virtual void func(){};
};
class F1:public F
{
public:
    virtual void func(){};
};


/*
 * 6、多重继承虚拟员函数
 */
class G
{
public:
    virtual void func(){};
};
class G1
{
public:
    virtual void func1(){};
};
class G2:public G,public G1
{
public:
    virtual void func(){};
    virtual void func1(){};
};

int main()
{
    /*
     * 1、编译器为了区别不同的空类实例对象,为空类内部默认增加了一个字节地址用于区分
     */
    A objA;
    StuA objA1;
    cout << "sizeof A " << sizeof (objA) << std::endl;         //output: 1
    cout << "sizeof StuA " << sizeof (objA1) << std::endl;   //output: 1


    /*
     * 2、类的非静态成员变量
     *  类的大小是每个成员变量的占用内存的大小。
     *  需要注意:有字节对齐规则:跟类中的成员变量类型最长的那个字节对对齐。
     *          所以,为了节省空间,写类成员变量时,类型大小最小字节的写在前面,
     *   或者最大类型字节的写在前面,只要按类型大小有序定义(降序/升序)就行!!!
     */
    B b;
    B1 b1;
    B2 b2;
    cout << "sizeof B " << sizeof (b) << std::endl;         //output: 8
    cout << "sizeof B1 " << sizeof (b1) << std::endl;       //output: 24
    cout << "sizeof B2 " << sizeof (b2) << std::endl;       //output: 16

    /*
     * 3、静态成员变量
     *  静态成员变量定义时就以及在全局/静态存储区分配了内存,不属于类对象。
     *  非其静态成员变量的内存是属于类对象的,每个类对象都会复制一份内存。
     *  静态成员变量只有一份,生存周期属于整个程序,所以不占用内对象的空间
     */
    C c;
    cout << "sizeof C " << sizeof (c) << std::endl;         //output: 1


    /*
     * 4、成员函数
     */
    D d;
    cout << "sizeof D " << sizeof (d) << std::endl;         //output: 1


    /*
     * 5、虚拟成员函数:虚函数表指针vptr指向需函数表vtable
     */
    E e;
    cout << "sizeof E " << sizeof (e) << std::endl;         //output: 8

    /*
     * 6、继承虚拟成员函数
     */
    F f;
    F1 f1;
    cout << "sizeof F " << sizeof (f) << std::endl;         //output: 8
    cout << "sizeof F1 " << sizeof (f1) << std::endl;         //output: 8

    /*
     * 7、多重继承虚拟成员函数
     *  继承两个虚函数表指针,不同的虚函数指针指向不同的虚函数
     */
    G2 g2;
    cout << "sizeof G2 " << sizeof (g2) << std::endl;         //output: 16
    return 0;
}

 执行结果如下:

9、菱形继承

菱形继承的继承关系如下:

菱形继承存在数据冗余问题,如上面D类里面会包含两份A的数据成员。解决方法使用虚继承。虚拟继承是指一个指定的基类,在继承体系结构中,将其成员数据实例共享给也从这个基类型直接或间接派生的其它类。

使用虚继承的写法如下:

详细介绍可以参考博客:C++继承、多继承、菱形继承、虚继承 (万字) - HJfjfK - 博客园 (cnblogs.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值