在什么情况下在 C++ 中使用 struct
与 class
更好?
C++ 中的 class
和 struct
之间的区别是:
默认情况下,结构成员和基类/结构是公共的。
默认情况下,类成员和基类/struts 是私有的。
类和结构都可以混合使用 public
、protected
和 private
成员,可以使用继承并可以具有成员函数。
我会推荐你:
将 struct 用于没有任何类特性的普通旧数据结构;
在使用私有或受保护成员、非默认构造函数和运算符等特性时使用类。
正如其他人所指出的那样,实际上只有两个实际的语言差异:
struct 默认为公共访问,class 默认为私有访问。
继承时,struct默认为public继承,class默认为private继承。 (具有讽刺意味的是,与 C++ 中的许多东西一样,默认值是向后的:公共继承是迄今为止更常见的选择,但人们很少声明结构只是为了节省键入“public”关键字的时间。
但实践中真正的区别在于声明构造函数/析构函数的 class
/struct
和不声明构造函数的 class
/struct
。 “plain-old-data” POD 类型有一定的保证,一旦你接管了类的构造,这些保证就不再适用了。为了清楚区分,许多人故意只对 POD 类型使用 struct
,如果他们要添加任何方法,请使用 class
。下面两个片段之间的区别在其他方面没有意义:
class X
{
public:
// ...
};
struct X
{
// ...
};
(顺便说一句,这里有一个关于“POD 类型”实际含义的很好解释的线程:What are POD types in C++?)
struct
还是 class
与您的对象是否为 POD 或是否应定义复制构造函数/析构函数无关。成员函数也与 POD 无关。当我重新阅读您所写的内容时,我发现您并没有提出其他建议,但是当前的措辞令人困惑
struct
和 class
之间的区别,而在对象布局方面则没有。自 C++11 以来,POD 的东西也发生了一些变化。不过,要点是正确的。当您使用任一关键字定义类时,它只是默认值。
现有答案中有很多误解。
Both class
and struct
declare a class.
是的,您可能必须在类定义中重新排列访问修改关键字,具体取决于您用于声明类的关键字。
但是,除了语法之外,选择其中之一的唯一原因是约定/风格/偏好。
有些人喜欢对没有成员函数的类坚持使用 struct
关键字,因为生成的定义“看起来像”来自 C 的简单结构。
同样,有些人喜欢对具有成员函数和 private
数据的类使用 class
关键字,因为它上面写着“类”,因此看起来像是他们最喜欢的面向对象编程书籍中的示例。
现实情况是,这完全取决于您和您的团队,它对您的程序没有任何影响。
以下两个类除了它们的名称外,在各方面都是绝对等价的:
struct Foo
{
int x;
};
class Bar
{
public:
int x;
};
您甚至可以在重新声明时切换关键字:
class Foo;
struct Bar;
(虽然 this breaks Visual Studio builds 由于不符合,所以编译器会在您执行此操作时发出警告。)
并且以下表达式的计算结果都为真:
std::is_class<Foo>::value
std::is_class<Bar>::value
但请注意,重新定义时不能切换关键字;这仅仅是因为(根据单一定义规则)跨翻译单元的重复类定义必须“由相同的标记序列组成”。这意味着您甚至不能将 const int member;
与 int const member;
交换,并且与 class
或 struct
的语义无关。
class foo { public: ... };
而另一个可以有 struct foo { ... };
根据“绝对等效”的说法必须成立。不完整的声明 struct foo;
和 class foo;
是可以互换的。这些不指定类主体,因此它们与访问布局无关。
Foo
和 Bar
仍然是等效/相同的类型.我确实确保说“当重新声明时”并举个例子。想想看,我会在答案中澄清这一点,以确保我不会误导人们进入 UB
我唯一一次使用结构而不是类是在函数调用中使用它之前声明一个仿函数并且为了清楚起见而希望最小化语法。例如:
struct Compare { bool operator() { ... } };
std::sort(collection.begin(), collection.end(), Compare());
从 C++ FAQ Lite:
结构的成员和基类默认是公共的,而在类中,它们默认是私有的。注意:您应该明确地使您的基类公开、私有或受保护,而不是依赖默认值。 struct 和 class 在其他方面在功能上是等效的。好的,足够干净的技术谈话了。从情感上讲,大多数开发人员在类和结构之间做出了强烈的区分。结构感觉就像是一堆开放的位,封装或功能的方式很少。一个类感觉就像是一个活生生的、负责任的社会成员,具有智能服务、强大的封装屏障和定义明确的接口。由于这是大多数人已经拥有的含义,因此如果您的类具有很少的方法并且具有公共数据(这样的东西确实存在于设计良好的系统中!),您可能应该使用 struct 关键字,否则您可能应该使用该类关键词。
结构对我有帮助的一个地方是当我有一个系统从另一个系统接收固定格式的消息(比如说,一个串行端口)时。您可以将字节流转换为定义字段的结构,然后轻松访问这些字段。
typedef struct
{
int messageId;
int messageCounter;
int messageData;
} tMessageType;
void processMessage(unsigned char *rawMessage)
{
tMessageType *messageFields = (tMessageType *)rawMessage;
printf("MessageId is %d\n", messageFields->messageId);
}
显然,这与您在 C 中所做的相同,但我发现必须将消息解码为类的开销通常不值得。
operator >>
而不是编写 processMessage
函数,这会使您的 C++ 看起来更像正确的 C++ 而不像 C。
void*
系统调用,并在C和C++之间传递,我说双赢?
char
类型,它不受别名的影响。然而,仍然存在一个问题,尽管是一个不同的问题:将 char*
转换为不同的类型,如果在该地址处实际上没有任何后一种类型的对象已经初始化,那么是 UB,因为它违反了生命周期规则。 Afaik,即使目标类型很容易构造,仅仅分配内存还不足以让 C++ 正式允许将该内存视为该类型。
如果您正在编写一个内部为 C++ 但 API 可以由 C 或 C++ 代码调用的库,则可以在 C++ 中使用“struct”。您只需创建一个包含结构和全局 API 函数的标头,您可以将它们公开给 C 和 C++ 代码,如下所示:
// C access Header to a C++ library
#ifdef __cpp
extern "C" {
#endif
// Put your C struct's here
struct foo
{
...
};
// NOTE: the typedef is used because C does not automatically generate
// a typedef with the same name as a struct like C++.
typedef struct foo foo;
// Put your C API functions here
void bar(foo *fun);
#ifdef __cpp
}
#endif
然后,您可以使用 C++ 代码在 C++ 文件中编写函数 bar() 并使其可从 C 调用,并且两个世界可以通过声明的结构共享数据。当然,在混合 C 和 C++ 时还有其他注意事项,但这是一个简化的示例。
正如每个人所说,唯一真正的区别是默认访问。但是当我不希望使用简单的数据类进行任何形式的封装时,我特别使用 struct,即使我实现了一些辅助方法。例如,当我需要这样的东西时:
struct myvec {
int x;
int y;
int z;
int length() {return x+y+z;}
};
对于 C++,结构和类之间确实没有太大区别。主要的功能区别是结构的成员默认是公共的,而它们在类中默认是私有的。否则,就语言而言,它们是等价的。
也就是说,我倾向于在 C++ 中使用结构,就像在 C# 中一样,类似于 Brian 所说的。结构体是简单的数据容器,而类用于除了保持数据之外还需要对数据进行操作的对象。
回答我自己的问题(无耻),如前所述,访问权限是 C++ 中它们之间的唯一区别。
我倾向于仅将结构用于数据存储。如果它可以更轻松地处理数据,我将允许它获得一些辅助函数。然而,一旦数据需要流控制(即维护或保护内部状态的 getter/setter)或开始获取任何主要功能(基本上更像对象),它将“升级”到一个类以更好地传达意图。
当您提供具有 C++ 实现的 C 兼容接口时,结构(PODs,更一般地说)很方便,因为它们可以跨语言边界和链接器格式移植。
如果这不是您关心的问题,那么我认为使用“结构”而不是“类”是一个很好的意图沟通者(正如上面的@ZeroSignal 所说)。结构还具有更可预测的复制语义,因此它们对于您打算写入外部媒体或通过网络发送的数据很有用。
结构体对于各种元编程任务也很方便,比如仅仅暴露一堆依赖类型定义的特征模板:
template <typename T> struct type_traits {
typedef T type;
typedef T::iterator_type iterator_type;
...
};
...但这实际上只是利用了结构的默认保护级别是公开的...
正如其他人指出的那样
除了默认可见性之外,两者都是等效的
无论出于何种原因,都可能有理由被迫使用其中一个或另一个
Stroustrup/Sutter 给出了关于何时使用 which 的明确建议:
如果类具有不变量,则使用类;如果数据成员可以独立变化,则使用 struct
但是,请记住,转发声明某事是不明智的。作为类 (class X;
) 并将其定义为结构 (struct X { ... }
)。它可能适用于某些链接器(例如,g++)并且可能在其他链接器(例如,MSVC)上失败,因此您会发现自己陷入了开发者的地狱。
class Foo; struct Foo { void bar() {} }; int main() { Foo().bar(); }
不仅可以与 MSVC 2017 一起编译和运行,它甚至会产生一个明确的警告,即 Foo
被声明为 struct
但定义为 class
。但我也清楚地记得,我们团队花了半天时间才找到那个愚蠢的错误。我不确定我们当时使用的是什么 MSVC 版本。
class
或 struct
,并且两者可以根据标准自由互换(尽管众所周知 VS 会发出警告;我总是假设这只是为了避免明显的程序员错误)。这里没有什么味道。您确定这不是 ODR 违规错误吗?
struct
-forwards 替换为 class
-forwards,问题就消失了。直到今天,我也觉得很奇怪。如果你能对此有所了解,我会很高兴。
struct
优于 class
的一个优点是它节省了一行代码,如果坚持“首先是公共成员,然后是私有的”。有鉴于此,我发现关键字 class
毫无用处。
这是只使用 struct
而从不使用 class
的另一个原因。一些 C++ 代码风格指南建议对函数宏使用小写字母,其基本原理是当宏转换为内联函数时,不需要更改名称。同样在这里。你有你漂亮的 C 风格的结构,有一天,你发现你需要添加一个构造函数,或者一些方便的方法。您是否将其更改为 class
?到处?
struct
和 class
之间的区别对于我们应该做的事情 - 编程来说太麻烦了。就像 C++ 的许多问题一样,它源于对向后兼容性的强烈渴望。
class
?您是否认为使用 struct
关键字定义的类不能有成员函数或构造函数?
class
关键字定义每个具有名为 joe()
的成员的类?每个至少有 4 个 int
成员的类都必须用 struct
关键字定义?
struct
定义的,具有方法的聚合是用 class
定义的”。太麻烦了。
它们几乎是一样的。由于 C++ 的魔力,结构可以像类一样保存函数、使用继承、使用“new”创建等等
唯一的功能区别是类以私有访问权限开头,而结构以公共访问权限开头。这是保持与 C 的向后兼容性。
在实践中,我一直将结构用作数据持有者,将类用作对象。
struct
和 class
在底层是相同的,但在可见性方面具有不同的默认值,struct
默认是公开的,而 class
默认是私有的。您可以通过适当使用 private
和 public
将其中一个更改为另一个。它们都允许继承、方法、构造函数、析构函数以及面向对象语言的所有其他优点。
然而,两者之间的一个巨大区别是 C 支持 struct
作为关键字,而 class
不支持。这意味着可以在包含文件中使用 struct
,只要 struct
是纯 C 样式 struct
并且包含文件中的所有其他内容都与C,即没有 C++ 特定的关键字,例如 private
、public
、没有方法、没有继承等等等等等等。
AC 样式 struct
可以与支持使用 C 样式 struct
在接口上来回传输数据的其他接口一起使用。
AC 样式 struct
是一种描述内存区域布局的模板(不是 C++ 模板,而是模式或模板)。多年来,已经创建了可从 C 和 C 插件(这里介绍 Java、Python 和 Visual Basic)使用的接口,其中一些接口与 C 风格struct
一起使用。
班级。
默认情况下,类成员是私有的。
class test_one {
int main_one();
};
相当于
class test_one {
private:
int main_one();
};
所以如果你尝试
int two = one.main_one();
我们将收到一个错误:main_one is private
,因为它不可访问。我们可以通过将其指定为公共来初始化它来解决它,即
class test_one {
public:
int main_one();
};
结构。
结构是一个类,其中成员默认是公共的。
struct test_one {
int main_one;
};
表示 main_one
是私有的,即
class test_one {
public:
int main_one;
};
我将结构用于成员可以取任何值的数据结构,这样更容易。
它们是相同的,具有不同的默认值(class
默认为私有,struct
默认为公共),因此理论上它们是完全可以互换的。
所以,如果我只是想打包一些信息来移动,我会使用一个结构,即使我在那里放了一些方法(但不是很多)。如果它是一个大部分不透明的东西,主要用途是通过方法,而不是直接对数据成员,我使用一个完整的类。
默认情况下,结构具有公共访问权限,而类默认情况下具有私有访问权限。
我个人将结构用于数据传输对象或值对象。当这样使用时,我将所有成员声明为 const 以防止其他代码修改。
只是从 C++20 标准的角度来解决这个问题(从 N4860 开始)......
class 是一种类型。关键字“class
”和“struct
”(和“union
”)是 - 在 C++ 语法中 - class-keys,并且选择 { 1} 或 struct
是:
class-key 确定 ... 访问默认是公共的还是私有的 (11.9)。
数据成员默认可访问性
11.9.1 中的示例记录了 class
关键字导致默认私有成员,而 `struct 关键字导致默认公开成员:
类 X { int a; // X::a 默认是私有的:使用的类
……对……
结构 S { int a; // S::a 默认是公共的:使用的结构体
基类默认可访问性
1.9 还说:
在基类没有访问说明符的情况下,当派生类使用类键结构定义时假定为公共,而当使用类键类定义类时假定为私有。
需要一致使用结构或类的情况......
有一个要求:
在类模板的重新声明、部分特化、显式特化或显式实例化中,类键应与原始类模板声明(9.2.8.3)在种类上一致。
...在任何详细的类型说明符中,枚举关键字应用于引用枚举(9.7.1),联合类键应用于引用联合(11.5),类或struct class-key 应用于引用非联合类 (11.1)。
提供了以下示例(不需要一致性时):
结构 S { } s;类 S* p = &s; // 好的
尽管如此,一些编译器可能会对此提出警告。
有趣的是,虽然您使用 struct
、class
和 union
创建的类型都称为“类”,但我们...
标准布局结构是使用 class-key 结构或 class-key 类定义的标准布局类。
...所以在标准语言中,当谈到标准布局结构时,它使用“结构”来暗示“不是联合”。
我很好奇在其他术语中是否有类似的“结构”使用,但是对标准进行详尽的搜索是一项太大的工作。欢迎评论。
typedef struct A A
并使用 struct A
或普通 A
来声明/定义变量等,但似乎事实并非如此。看来您可以以这种方式同时使用 struct
或 class
。
经过多年使用我的主要语言 C++ 进行编程,我得出一个死结论,即这是 C++ 的另一个愚蠢特性。
两者之间没有真正的区别,也没有理由我应该花额外的时间来决定我应该将我的实体定义为结构还是类。
要回答这个问题,请随时将您的实体定义为结构。默认情况下,成员将是公开的,这是常态。但更重要的是,默认情况下继承是公开的。受保护的继承,甚至更糟糕的是私有继承,都是例外。
我从来没有遇到过私人继承是正确做法的案例。是的,我试图发明使用私有继承的问题,但没有奏效。而Java,如果不使用访问器关键字,面向对象编程的角色模型默认为公共继承。顺便说一句,Java 不允许在继承类上使用访问器关键字,它们只能被公开继承。所以你可以看到,cpp团队真的在这里倒下了。
另一个令人沮丧的事情是,如果你定义为一个类并声明为一个结构,你会收到编译警告。好像这会影响程序的性能或准确性。一个答案还指出,MSVC 可能会传播编译器错误。
那些在下雨时使用课程,在阳光下使用结构的人是根据他们所教的内容这样做的。他们发现这不是真的。 Java 没有一对类的名称,只有 class 关键字。如果你想要一个数据结构,只需将所有成员公开,不要添加函数。这在 Java 中有效,我没有看到任何问题。有什么问题?您需要 4 或 5 个 BOM 代码字符来确定如何解释类实体的上下文。
struct
。
从技术上讲,两者在 C++ 中是相同的 - 例如,结构可能具有重载运算符等。
然而 :
当我希望同时传递多种类型的信息时,我使用结构。当我处理“功能”对象时,我使用类。
希望能帮助到你。
#include <string>
#include <map>
using namespace std;
struct student
{
int age;
string name;
map<string, int> grades
};
class ClassRoom
{
typedef map<string, student> student_map;
public :
student getStudentByName(string name) const
{ student_map::const_iterator m_it = students.find(name); return m_it->second; }
private :
student_map students;
};
例如,我在这里的 get...() 方法中返回了一个 struct student - 享受吧。
在 C++ 中,您何时选择使用 struct 以及何时使用 class?
我在定义 functors
和 POD
时使用 struct
。否则我使用 class
。
// '()' is public by default!
struct mycompare : public std::binary_function<int, int, bool>
{
bool operator()(int first, int second)
{ return first < second; }
};
class mycompare : public std::binary_function<int, int, bool>
{
public:
bool operator()(int first, int second)
{ return first < second; }
};
std::binary_function<>
不仅已弃用,c ++ 17甚至将其删除。
当我需要创建 POD 类型或仿函数时,我会使用结构。
默认情况下,所有类成员都是私有的,默认情况下所有结构成员都是公共的。类具有默认的私有基础,而 Struct 具有默认的公共基础。在 C 的情况下,结构不能具有成员函数,而在 C++ 的情况下,我们可以将成员函数添加到结构中。除了这些差异之外,我没有发现任何令人惊讶的地方。
仅当我需要保存一些数据而没有任何关联的成员函数(对成员数据进行操作)并直接访问数据变量时,我才使用 struct。
例如:从文件和套接字流等读取/写入数据。在函数参数太多且函数语法看起来太冗长的结构中传递函数参数。
从技术上讲,除了默认可访问性之外,类和结构之间没有太大区别。更重要的是,它取决于您如何使用它的编程风格。
想要改进这篇文章?提供这个问题的详细答案,包括引文和解释为什么你的答案是正确的。没有足够细节的答案可能会被编辑或删除。
我认为 Structs 旨在作为一种数据结构(如信息的多数据类型数组),而类则用于代码打包(如子例程和函数的集合)。
:(
我从不在 C++ 中使用“结构”。
我无法想象当你想要私有成员时你会使用结构的场景,除非你故意试图混淆。
似乎使用结构更多地是对如何使用数据的句法指示,但我宁愿只创建一个类并尝试以类的名称或通过注释来明确说明。
例如
class PublicInputData {
//data members
};
struct
不是已经非常明确地表明该类的成员默认情况下是公共的吗?