C++中struct和class的区别是什么?

494

这个问题已经在C#/.Net的上下文中被问及过

现在我想学习C++中结构体和类的区别。请讨论技术差异以及在面向对象设计中选择其中一个的原因。

我将从一个明显的区别开始:

  • 如果没有指定public:private:,结构体的成员默认为public;类的成员默认为private。

我相信在C++规范的晦涩角落还可以找到其他差异。


9
这个链接很好地总结了这些差异。 - sjsam
1
为什么人们都使用结构体来构建树呢?因为它们之间的差异似乎并不大。顺便说一下,这个 是一个很棒的网站。@sjsam - JW.ZG
1
想了解C和C++中struct的区别吗?请看这里 - Marc.2377
@JW.ZG 并不是“所有”人都这样做!那些这样做的人要么只是喜欢这样做,要么就是没有意识到在 C++ 中 struct 的含义。;) 但你完全可以使用 class 关键字来代替。 - Lightness Races in Orbit
29个回答

496

您忘记了类和结构体之间的棘手区别。

引用标准(§11.2.2 in C++98 through C++11):

在派生类声明为struct时,如果一个基类缺少访问说明符,则默认情况下使用public;如果一个基类缺少访问说明符,则默认情况下使用private。

为了完整起见,class和struct之间更广为人知的差异在(11.2)中定义:

使用class关键字定义的类的成员默认为private。使用structunion关键字定义的类的成员默认为public

额外的差异:关键字class可以用于声明模板参数,而struct关键字不能这样使用。


27
这并不是第二个差别,只是问题陈述不完整。使用 class 时,所有子对象默认为私有,而使用 struct 则默认为公共,两者都定义了一个类类型。 - Ben Voigt
12
我觉得你误解了重点,Ben。对于结构体来说,继承是公开的,而对于类来说,继承是私有的。这是一个非常重要的区别,与实际成员访问没有任何关系。例如,语言可以很好地定义另一种情况,即默认情况下两者都是公开继承的,这将产生非常不同的影响。 - Assaf Lavie
114
实际上,“struct”和“class”之间真正棘手的区别是,后者可以用来代替“typename”以声明模板参数,而前者则不能。 :) - sbi
21
@MrUniverse:这完全是错误的。(有一所学校在会议上使用了这种语法,但它并没有被强制执行。) - sbi
3
“struct” 和 “class” 的真正棘手区别是什么?@sbi说:“可爱,但问题是关于一个结构体和一个类之间的区别,而不是关于关键字可以在哪里使用的区别。” - Jim Balter
显示剩余8条评论

180

引用C++ FAQ的话:

[7.8]关键字struct和class有什么区别?

一个结构体(struct)的成员变量和继承类默认为 public,而类(class)默认为 private。注意: 应该明确指定基类为public、private或protected,而不是依赖默认值。

在其他方面,struct和class具有相同的功能。

好的,够了这种干净利落的技术说法。情感上,大多数开发人员对类和结构体之间有很强的区别。结构体仅仅感觉像是一个开放的位桶,几乎没有封装或功能。类感觉像是一个生活在社会中并拥有智能服务、强封装屏障和良好定义接口的负责任成员。由于这是大多数人已经有的内涵,如果你有一个只有很少方法和公共数据的类(在设计良好的系统中确实存在这样的事情!),那么你应该使用struct关键字,但否则你应该使用class关键字。


141
值得记住的是C++的起源和与C的兼容性。
在C中,有结构体,但没有封装的概念,所以一切都是公开的。
默认情况下是公开的通常被认为是采用面向对象方法时不好的想法,因此在创建本地支持OOP的C形式时(您可以在C中执行OO,但不会对您有帮助),这就是C ++(最初的“C ++ with Classes”)的想法,通过默认设置成员为私有,这是有道理的。
另一方面,如果Stroustrup更改了struct的语义,使其成员默认为私有,它将破坏兼容性(随着标准分歧不再常见,但所有有效的C程序也是有效的C ++程序,这对于使C ++ 扎根产生了重大影响)。
因此,引入了一个新的关键字class,与struct完全相同,但默认情况下是私有的。
如果C ++从头开始而没有历史记录,那么它可能只有一个这样的关键字。它也可能不会产生它所产生的影响。
通常,当人们做类似于C中使用结构体的事情时,他们倾向于使用结构体;公共成员,无构造函数(只要它不在联合中,你可以在结构体中使用构造函数,就像在类中一样,但人们 tend not to),没有虚方法等。由于语言与阅读代码的人交流的重要性也不亚于指导机器(否则我们将坚持汇编和原始VM操作码),因此最好坚持这种做法。

1
值得注意的是,在底层让类和结构体工作方式相同可能比让它们根本不同更容易。回顾起来,例如指定任何声明为结构体的内容必须是PODS(即禁止结构体具有虚成员、非平凡默认构造函数或析构函数等)可能会有一些好处,但据我所知,任何C++标准或实现都没有要求这样做。 - supercat
1
@supercat,它是一种面向对象的语言,其中大量用非面向对象语言编写的程序也是有效的程序,这一概念引起了人们的关注,在更纯粹的面向对象语言中似乎更常见(当然在标准中也有明确定义)。早期C++的历史确实解释了很多问题。Stroustrup的《C++设计与演化》是一本有趣的读物。 - Jon Hanna
1
我认为在那些认为除了"面向对象"之外的一切都应该是面向对象的人和那些认为面向对象只是一种工具而不是唯一工具的人之间存在着一场宗教战争。C++显然采用了后一种哲学,但我对它之前的语言并不了解。我的哲学是,当一个人想要一个对象时,就应该使用一个对象,当一个人想要相关但独立的变量的聚合体时,就应该使用那个聚合体。C++在这些事情之间没有语法上的区别,而.NET试图模糊这种区别,但我所知道的关于D的一点... - supercat
1
它表明它比C++或.NET更加认可。变量的聚合并不完全是面向对象的,但这并不意味着在它们有用时不应该使用它们。 - supercat
3
我不同意“C有结构体,但它没有封装的概念,因此一切都是公开的”这种说法。你可以将struct的定义隐藏在*.c文件中,并让其他翻译单元只能通过指针来使用它。因此,你拥有更强的封装性,因为其他翻译单元甚至不知道struct里面有什么。 - 12431234123412341234123
显示剩余3条评论

36

类的成员默认为私有,结构体的成员默认为公共。除此之外,没有其他区别。另请参见此问题


15
不仅适用于成员,还包括继承在内的所有访问权限。 - Nemanja Trifunovic
4
我认为另一个区别在于语义学。对许多人来说,Struct 让他们想起了 C 语言中的“数据结构”。 - Kris Kumler
3
@KrisKumler:这些不是“语义学”; 它们是个人感受。 structclass 都声明了一个具有相同语义的 _类_(尽管在解析定义体时可能会有不同的理解)。 - Lightness Races in Orbit

32
根据 Stroustrup 在 C++编程语言 中的说法:

你使用哪种风格取决于情况和口味。我通常更喜欢将 struct 用于所有数据都是公共的类。我认为这样的类是“不太合适的类型,只是数据结构”。

在功能上,除了 public/private 外没有任何区别。


33
有何不同?请解释。 - crashmstr

15
  1. 类的成员默认为私有,结构体的成员默认为公有

例如,程序1编译失败,而程序2可以正常工作。

// Program 1
#include <stdio.h>
 
class Test {
    int x; // x is private
};

int main()
{
  Test t;
  t.x = 20; // compiler error because x is private
  getchar();
  return 0;
}

// Program 2
#include <stdio.h>
 
struct Test {
    int x; // x is public
};

int main()
{
  Test t;
  t.x = 20; // works fine because x is public
  getchar();
  return 0;
}
  1. 从一个类/结构派生一个结构时,默认的访问说明符为public。当从一个类派生时,默认访问说明符为private。

例如,程序3编译失败而程序4正常工作。

// Program 3
#include <stdio.h>
 
class Base {
public:
    int x;
};
 
class Derived : Base { }; // is equivalent to class Derived : private Base {}
 
int main()
{
  Derived d;
  d.x = 20; // compiler error because inheritance is private
  getchar();
  return 0;
}

// Program 4
#include <stdio.h>
 
class Base {
public:
    int x;
};
 
struct Derived : Base { }; // is equivalent to struct Derived : public Base {}
 
int main()
{
  Derived d;
  d.x = 20; // works fine because inheritance is public
  getchar();
  return 0;
}

我已经按照专家的建议删除了代码示例3-7。 - Suraj K Thomas

11

STRUCT是一种抽象数据类型,根据结构规范将给定的内存块分成不同的部分。在文件序列化/反序列化中,STRUCT很有用,因为结构体通常可以直接写入文件。(即:获取指向结构体的指针,使用SIZE宏计算要复制的字节数,然后移动结构体中的数据进出)

类是另一种抽象数据类型,旨在确保信息隐藏。内部可能会有各种操纵、方法、临时变量、状态变量等,所有这些都用于向想要使用类的任何代码提供一致的API。

实际上,structs关注于数据,而classes关注于代码。

但您需要了解这些仅仅是抽象。完全可以创建看起来像类的structs和看起来像structs的classes。事实上,最早期的C++编译器只是将C++代码转换为C的预编译器。因此,这些抽象是有益于逻辑思维的,不一定是计算机本身的资产。

除了它们是不同类型的抽象之外,类还提供了解决C代码命名难题的解决方案。由于不能公开具有相同名称的多个函数,开发人员曾经遵循_()模式。例如:mathlibextreme_max()。通过将API分组到类中,类似的函数(这里称为“方法”)可以分组在一起,并受到来自其他类方法命名的保护。这使程序员能够更好地组织代码并增加代码重用。至少理论上是这样。


2
这是关于结构体和类最不显而易见的事情。可以将“结构体是关于数据的,类是关于代码的”重新表述为“结构体是关于数据的,类是关于数据、安全性以及对此数据执行的操作的”。 - Arun Aravind
4
在C++中,无法创建结构体。只能使用继承的“struct”关键字创建类。 - Lightness Races in Orbit
2
这个答案似乎与C++无关。在C++中,struct声明类(包括public/private/protected、继承等)。 - melpomene
1
结构体如何抽象化?即使在C语言中,将原始结构体写入文件也存在许多问题(常见问题包括填充、字节序、不同的字长等)。你所说的“SIZE”宏是什么? - melpomene

8
唯一的另一个区别在于类和结构体的默认继承方式,分别是私有和公有。

6

classstruct的区别是关键字之间的差异,而不是数据类型之间的差异。

struct foo : foo_base { int x;};
class bar : bar_base { int x; };

两者都定义了一个类类型。这个上下文中关键词的不同之处在于默认访问权限不同:

  • foo::x为公共(public),foo_base以公共方式继承
  • bar::x为私有(private),bar_base以私有方式继承

5
  1. 结构体的成员默认是公共的,类的成员默认是私有的。
  2. 一个结构体可以从另一个结构体或者类中继承得到公共成员。一个类可以从另一个结构体或者类中继承得到私有成员。
class A{    
public:    
    int i;      
};

class A2:A{    
};

struct A3:A{    
};


struct abc{    
    int i;
};

struct abc2:abc{    
};

class abc3:abc{
};


int _tmain(int argc, _TCHAR* argv[])
{    
    abc2 objabc;
    objabc.i = 10;

    A3 ob;
    ob.i = 10;

    //A2 obja; //privately inherited
    //obja.i = 10;

    //abc3 obss;
    //obss.i = 10;
}

这是关于VS2005的。


1
_tmain不是标准的C++。 - melpomene

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接