一、基础语法差异

1.1 访问修饰符差异

  • class 默认成员访问权限为 private
    • 声明的成员变量与函数仅对类内部可见,需使用 public/protected 显式开放
  • struct 默认成员访问权限为 public
    • 结构体成员对所有作用域开放,需使用 private/protected 显式限制
1
2
3
4
5
6
7
8
9
10
class MyClass {
int privateVar; // 默认私有
public:
void publicFunc() {}
};

struct MyStruct {
int publicVar; // 默认公有
void publicFunc() {}
};

1.2 成员函数特性

  • class 支持抽象方法(纯虚函数)
    • 通过 = 0 定义的虚函数使类成为抽象类,如 virtual void func() = 0;
  • struct 不支持抽象方法
    • 所有成员函数必须有具体实现,否则会导致编译错误
1
2
3
4
5
6
7
8
class AbstractClass {
public:
virtual void abstractFunc() = 0; // 纯虚函数
};

struct BadStruct {
virtual void abstractFunc() = 0; // 编译错误:struct不支持抽象方法
};

1.3 构造函数行为

  • class 必须显式定义构造函数
    • 提供默认构造函数需使用 MyClass() {} 显式声明
  • struct 可以省略构造函数
    • 编译器会自动合成默认构造函数
1
2
3
4
5
6
7
8
class MyClass {
public:
MyClass() {} // 显式定义
};

struct MyStruct {
// 编译器自动生成默认构造函数
};

1.4 继承机制差异

  • class:传统支持多继承(C++继承机制默认为 private)
  • struct:C++11后支持多继承(继承方式默认为 public)
    • 例如:struct Derived : Base1, Base2 { }; 合法
1
2
3
struct Base1 {};
struct Base2 {};
struct MultiDerived : Base1, Base2 { }; // C++11合法

二、实现机制解析

2.1 内存布局差异

  • 类与结构体同构:成员变量按声明顺序排列,遵循内存对齐规则
  • 差异点:类中隐式包含的虚函数表指针(vptr)会导致额外内存开销
    • 例如:带有虚函数的类会包含一个 vptr 成员,而结构体通常不包含该指针
1
2
3
4
5
6
7
8
9
struct Data {
int a;
double b;
}; // 内存布局更紧凑

class Base {
public:
virtual void func() {} // 含有vptr
}; // 增加4字节虚函数表指针

2.2 类型转换机制

  • class 的构造函数默认参与隐式类型转换
    • 编译器可将构造函数视为转换运算符,如 MyClass obj = 42;
  • struct 的构造函数也默认参与隐式类型转换
    • 但可通过 explicit 限制转换行为
1
2
3
4
5
6
7
8
9
class MyClass {
public:
MyClass(int x) {}
};

struct MyStruct {
public:
explicit MyStruct(int x) {} // 防止隐式转换
};

2.3 名字遮蔽规则

  • 类与结构体统一遵循:子类同名成员遮蔽基类成员
  • 差异点:结构体在继承中可定义同名构造函数,其行为与基类构造函数差异化
    • 例如:struct Derived : Base { Derived() {} }; 会遮蔽 Base 的构造函数
1
2
3
4
5
6
7
struct Base {
Base() {}
};

struct Derived : Base {
Derived() {} // 遮蔽Base的构造函数
};

2.4 编译器优化策略

  • 内存对齐差异:编译器可能对结构体应用更严格的对齐规则
  • 性能差异:结构体的默认构造函数合成效率通常高于类
  • 实现细节:某些编译器(如MSVC)对结构体的内存布局可能更紧凑
1
2
3
4
5
// 结构体可能导致更紧凑的内存布局
struct Point {
int x;
int y;
};

三、应用场景对比

3.1 数据封装场景

  • class 适用性:需要封装数据与行为的完整对象
    • 示例:class Student { private: int id; public: void study() {} };
  • struct 适用性:纯数据结构(C++11优化后适用复杂场景)
    • 示例:struct Point { int x; int y; };

3.2 继承体系构建

  • class 适用性:构建复杂的继承树,支持多继承与多态
    • 示例:class Shape { virtual void draw() {} }; class Circle : Shape { void draw() override {} };
  • struct 适用性:支持多继承但通常用于非多态场景
    • 示例:struct Shape { virtual void draw() {} }; struct Square : Shape { void draw() override {} };

3.3 代码设计模式

  • Pimpl惯用法:class更适合封装实现细节
    • 示例:class MyClass { private: std::unique_ptr<Implementation> pimpl; };
  • 值类型设计:struct更适合轻量级值类型(C++11后适用)
    • 示例:struct MyValue { int a; int b; };

3.4 性能敏感场景

  • class 适用性:结构复杂时可能不适用于性能关键路径
  • struct 适用性:内存占用更少,更适合底层数据处理
    • 示例:struct Buffer { unsigned char data[1024]; };

四、核心差异总结

特性 class struct
默认访问权限 private public
抽象方法支持 支持 不支持
默认构造函数 需显式声明或合成 自动合成
虚函数表 含有(若定义虚函数) 通常不含
隐式转换 支持 支持(可通过explicit限制)
继承方式 传统使用public继承 C++11后支持public继承
编译器处理 按标准严格处理 可能有更紧凑的优化