深入剖析struct与class

本文探讨了C++中struct与class的区别,特别是内存布局方面。当struct不含有虚函数时,其数据成员的声明顺序与内存偏移保持一致。而class在满足POD(Plain Old Data)原则时,内存布局才会与struct相同。POD类型主要用于C++与C之间的兼容性,允许C++程序与C函数交互。要成为POD类型,必须满足平凡的构造函数、析构函数等条件,并且不能包含虚函数或虚拟基类。文章详细阐述了满足POD原则的条件和标准布局的定义。

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

谈到struct和class的区别,我们的第一反应就是struct也可以和class一样拥有多态,继承的特性,最大的不同只是他们的默认权限不同,struct默认访问权限是public,class默认权限是private,但其实还有一点:memory layout可能不同。

struct(没有使用虚函数)的数据成员声明顺序和这些数据成员在内存中的offset一定是一致的。而class只有在POD原则(Plain Old Data)下才与struct的memory layout一致。

那么问题来了什么是满足POD原则的class?

POD数据类型

概念

POD数据类型主要用来解决C++与C之间数据类型的兼容性,以实现C++程序与C函数的交互。

  • POD类型(plain old data),与C兼容的原始数据,例如,结构体和整型等C语言中的类型是POD类型,而带有用户自定义的构造函数或虚函数的类则不是(指针类型也是POD类型)
    • string t_obj1(“cppcourase”); //错误,不能调用对象的构造函数
    • string* t_obj2 = new string; //错误,初始化只能是编译期常量
    • string* t_obj3 = NULL; //正确

什么情况下满足POD原则

C++11中把POD分为了两个基本概念的集合,即:平凡的(trival)和标准布局的(standard layout)。只有满足这两个基本概念才能称为是POD类型。

  • 拥有平凡的默认构造函数(trivial constructor)和析构函数(trivial destructor)
  • 拥有平凡的复制构造函数(trivial copy constructor)和移动构造函数(trivial move constructor)
  • 拥有平凡的复制赋值运算符(trivial assignment operator)和移动赋值运算符(trivial move operator)
  • 不能包含虚拟函数和虚拟基类

trivial指由编译器默认提供的,而不是用户自定义的

一个standard layout的class或者struct应该符合以下定义:

  • 没有 non-standard-layout类型(或这些类型的数组)和引用的非静态数据成员
  • 没有虚函数和虚基类
  • 非静态数据成员的访问控制必须是相同的
  • 没有non-standard-layout的基类
  • 在class或者struct继承时,满足以下两种情况之一的class或者struct也是标准布局的:
    • 派生类中有非静态成员,且只有一个仅包含静态成员的基类
    • 基类有非静态成员,而派生类没有非静态成员
  • 相同基类类型的非静态数据成员不能作为第一个成员

示例:

// empty classes have standard-layout
struct StandardLayout1 {};

struct StandardLayout2 {
    int x;
};

struct StandardLayout3 {
private: // both are private, so it's ok
    int x;
    int y;
};

struct StandardLayout4 : StandardLayout1 {
    int x;
    int y;

    void f(); // perfectly fine to have non-virtual functions
};

struct StandardLayout5 : StandardLayout1 {
    int x;
    StandardLayout1 y; // can have members of base type if they're not the first
};

struct StandardLayout6 : StandardLayout1, StandardLayout5 {
    // can use multiple inheritance as long only
    // one class in the hierarchy has non-static data members
};

struct StandardLayout7 {
    int x;
    int y;
    StandardLayout7(int x, int y) : x(x), y(y) {} // user-provided ctors are ok
};

struct StandardLayout8 {
public:
    StandardLayout8(int x) : x(x) {} // user-provided ctors are ok
// ok to have non-static data members and other members with different access
private:
    int x;
};

struct StandardLayout9 {
    int x;
    static NonStandardLayout1 y; // no restrictions on static members
};

struct NonStandardLayout1 {
    virtual f(); // cannot have virtual functions
};

struct NonStandardLayout2 {
    NonStandardLayout1 X; // has non-standard-layout member
};

struct NonStandardLayout3 : StandardLayout1 {
    StandardLayout1 x; // first member cannot be of the same type as base
};

struct NonStandardLayout4 : StandardLayout3 {
    int z; // more than one class has non-static data members
    };

struct NonStandardLayout5 : NonStandardLayout3 {}; // has a non-standard-layout base class
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值