struct默认public继承和public成员,class默认private继承和private成员;语义上struct多用于纯数据聚合,class用于封装逻辑;模板特化时关键字须与声明一致;聚合初始化取决于类型是否为聚合类,与关键字无关。

struct 默认是 public 继承和 public 成员
这是最直接、最常被忽略的差异。C++ 中 struct 和 class 语法几乎完全等价,唯一默认行为不同:
- struct 的默认继承方式是 public,默认成员访问权限也是 public;
- class 的默认继承方式是 private,默认成员访问权限也是 private。
也就是说,下面两个定义在行为上完全等价:
struct A {
int x;
void f() {}
};
// 等价于
class A {
public:
int x;
void f() {}
};但如果你写:
struct B : A { int y; }; // 默认 public 继承
class C : A { int y; }; // 默认 private 继承 → C 不是 A 的公有子类这时候 C 无法被当作 A 使用(比如不能传给接受 A& 的函数),而 B 可以——这个区别在模板推导、多态和接口设计中会悄悄出问题。
语义习惯与 ABI 兼容性影响实际使用
虽然语言层面 struct 和 class 可互换,但 C++ 社区有强约定:
-
struct多用于纯数据聚合(POD 或标准布局类型),比如Point、Config、C 接口封装; -
class多用于封装逻辑、隐藏实现、提供不变式(如std::vector、std::string)。
这种习惯不是语法强制,但会影响:
-
ABI 兼容性:带虚函数、非 trivial 构造/析构的
class可能改变内存布局;而纯struct更容易与 C 互操作; -
编译器优化:某些场景下(如聚合初始化、结构体拷贝),编译器对
struct更倾向按字节处理; -
代码可读性:看到
struct S { int a, b; };,读者默认不期待它有复杂生命周期管理;看到class FileHandle,立刻警惕资源释放逻辑。
模板参数和特化时 struct/class 不能混用
模板声明里用 class T 还是 typename T 是语法习惯,但显式特化时,struct 和 class 关键字必须和原始声明一致——否则编译器报错:
iHuzuCMS狐族内容管理系统,是国内CMS市场的新秀、也是国内少有的采用微软的ASP.NET 2.0 + SQL2000/2005 技术框架开发的CMS,充分利用ASP.NET架构的优势,突破传统ASP类CMS的局限性,采用更稳定执行速度更高效的面向对象语言C#设计,全新的模板引擎机制, 全新的静态生成方案,这些功能和技术上的革新塑造了一个基础结构稳定功能创新和执行高效的CMS。iHuzu E
templatestruct Container { /* ... */ }; template<> struct Container { /* OK,匹配原始声明 */ }; template<> class Container
{ / ERROR:原始声明是 struct,这里写 class 不合法 / };
同样,如果原始声明是 template,特化就必须用 class X,不能写 struct X。这不是风格问题,是语法硬性要求。
聚合初始化只认 struct/class 的“聚合”本质,不认关键字
能否用 {...} 初始化,取决于类型是否为「聚合类」(aggregate),跟写的是 struct 还是 class 无关。只要满足:
- 无用户声明的构造函数;
- 无私有/保护的非静态数据成员;
- 无基类;
- 无虚函数;
- 无默认成员初始化器(C++11 起放宽,但带默认初始化器仍可能破坏聚合性);
那它就能聚合初始化。例如:
class Vec3 {
public:
float x, y, z;
}; // 没有构造函数、全是 public 成员 → 是聚合类 → Vec3 v{1,2,3}; 合法
struct Bad {
private:
int x;
}; // 有 private 成员 → 不是聚合类 → Bad b{1}; 非法
所以别以为写了 struct 就一定支持 {} 初始化——得看实际成员和函数,而不是关键字本身。
真正容易踩坑的地方在于:把 struct 当成“轻量级 class”随意加构造函数、虚函数或私有成员,结果发现它突然不能 POD、不能 memcpy、不能和 C 二进制兼容了。关键字只是起点,决定行为的是你实际写的那些东西。









