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

目录

1、空类

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

3、包含静态成员变量类

4、包含普通成员函数类

5、包含虚函数类

6、继承虚函数类

7、多重继承类

8、虚函数表


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

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

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

1、空类

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

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

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

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

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

3、包含静态成员变量类

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

4、包含普通成员函数类

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

5、包含虚函数类

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

虚函数表可参考链接:

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

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

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

6、继承虚函数类

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

关于虚函数表可参考:

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

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

7、多重继承类

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

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

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

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

8、虚函数表

虚函数表可参考:

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

demo代码如下:

#include 

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;
}

 执行结果如下:

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

你可能感兴趣的:(C/C++语言,c++,开发语言)