在什么情况下在 C++中使用 a struct
vs a更好?class
27 回答
C++ 中的 aclass
和 a的区别在于:struct
struct
成员和基类/结构是public
默认的。class
默认情况下,成员和基类/支柱private
。
类和结构都可以混合使用和成员public
,可以使用继承并且可以具有成员函数。protected
private
我会推荐你:
- 用于
struct
没有任何类特征的普通旧数据结构; - 在使用or成员、非默认构造函数和运算符等
class
特性时使用。private
protected
正如其他人所指出的那样,实际上只有两个实际的语言差异:
struct
默认为公共访问,class
默认为私有访问。- 继承时,
struct
默认为public
继承,class
默认为private
继承。(具有讽刺意味的是,与 C++ 中的许多东西一样,默认值是向后的:public
继承是迄今为止更常见的选择,但人们很少声明struct
s 只是为了节省键入“public
”关键字的时间。
但实践中真正的区别在于声明构造函数class
/struct
析构函数的 / 和不声明构造函数/析构函数的 / 之间。“plain-old-data” POD 类型有一定的保证,一旦你接管了类的构造,这些保证就不再适用了。为了清楚区分,许多人故意只将struct
s 用于 POD 类型,如果他们要添加任何方法,请使用class
es。下面两个片段之间的区别在其他方面没有意义:
class X
{
public:
// ...
};
struct X
{
// ...
};
(顺便说一句,这里有一个线程对“POD 类型”的实际含义进行了一些很好的解释:什么是 C++ 中的 POD 类型?)
现有答案中有很多误解。
是的,您可能必须在类定义中重新排列访问修改关键字,具体取决于您用于声明类的关键字。
但是,除了语法之外,选择其中之一的唯一原因是约定/风格/偏好。
有些人喜欢为没有成员函数的类坚持使用struct
关键字,因为生成的定义“看起来像”来自 C 的简单结构。
类似地,有些人喜欢class
为具有成员函数和数据的类使用关键字private
,因为它上面写着“类”,因此看起来像是他们最喜欢的面向对象编程书籍中的示例。
现实情况是,这完全取决于您和您的团队,它对您的程序没有任何影响。
以下两个类除了它们的名称外,在各方面都是绝对等价的:
struct Foo
{
int x;
};
class Bar
{
public:
int x;
};
您甚至可以在重新声明时切换关键字:
class Foo;
struct Bar;
(尽管这会由于不符合而破坏 Visual Studio 构建,因此编译器会在您执行此操作时发出警告。)
并且以下表达式的计算结果都为真:
std::is_class<Foo>::value
std::is_class<Bar>::value
但请注意,重新定义时不能切换关键字;这仅仅是因为(根据单一定义规则)跨翻译单元的重复类定义必须“由相同的标记序列组成”。这意味着您甚至不能const int member;
与交换,并且与orint const member;
的语义无关。class
struct
我唯一一次使用结构而不是类是在函数调用中使用它之前声明一个仿函数并且为了清楚起见而希望最小化语法。例如:
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 中所做的相同,但我发现必须将消息解码为类的开销通常不值得。
如果您正在编写一个内部为 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 兼容的接口时,结构(更一般地说是POD )很方便,因为它们可以跨语言边界和链接器格式移植。
如果这不是您关心的问题,那么我认为使用“结构”而不是“类”是一个很好的意图沟通者(正如上面的@ZeroSignal 所说)。结构还具有更可预测的复制语义,因此它们对于您打算写入外部媒体或通过网络发送的数据很有用。
结构体对于各种元编程任务也很方便,比如仅仅暴露一堆依赖类型定义的特征模板:
template <typename T> struct type_traits {
typedef T type;
typedef T::iterator_type iterator_type;
...
};
...但这实际上只是利用了结构的默认保护级别是公开的...
正如其他人指出的那样
- 除了默认可见性之外,两者都是等效的
- 无论出于何种原因,都可能有理由被迫使用其中一个或另一个
Stroustrup/Sutter 给出了关于何时使用 which 的明确建议:
但是,请记住,转发声明某事是不明智的。作为一个类 ( class X;
) 并将其定义为 struct ( struct X { ... }
)。它可能适用于某些链接器(例如,g++)并且可能在其他链接器(例如,MSVC)上失败,因此您会发现自己陷入了开发者的地狱。
它们几乎是一样的。由于 C++ 的魔力,结构可以像类一样保存函数、使用继承、使用“new”创建等等
唯一的功能区别是类以私有访问权限开头,而结构以公共访问权限开头。这是保持与 C 的向后兼容性。
在实践中,我一直将结构用作数据持有者,将类用作对象。
struct
over的一个优点class
是它节省了一行代码,如果坚持“首先是公共成员,然后是私有的”。在这种情况下,我发现关键字class
没用。
struct
这是使用 only和 never的另一个原因class
。一些 C++ 代码风格指南建议对函数宏使用小写字母,其基本原理是当宏转换为内联函数时,不需要更改名称。同样在这里。你有你漂亮的 C 风格的结构,有一天,你发现你需要添加一个构造函数,或者一些方便的方法。你把它改成class
? 到处?
区分struct
s 和class
es 实在是太麻烦了,进入我们应该做的事情的方式——编程。就像 C++ 的许多问题一样,它源于对向后兼容性的强烈渴望。
两者struct
和class
在引擎盖下都是相同的,尽管在可见性方面具有不同的默认值,struct
默认值是公共的,class
默认值是私有的。private
您可以通过适当使用和将其中一个更改为另一个public
。它们都允许继承、方法、构造函数、析构函数以及面向对象语言的所有其他优点。
然而,两者之间的一个巨大区别是,struct
在 C 中支持关键字,class
而不支持。这意味着可以在包含文件中使用 a struct
,该包含文件可以#include
是 C++ 或 C,只要它struct
是纯 C 样式struct
并且包含文件中的所有其他内容都与 C 兼容,即没有 C++ 特定的关键字,例如private
, public
, no方法,没有继承,等等等等等等。
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
”和“ struct
”(和“ union
”)是——在C++语法中——class -key,选择class
or的唯一功能意义struct
是:
class-key确定 ... 访问默认是公共的还是私有的 (11.9) 。
数据成员默认可访问性
11.9.1 中的示例记录了class
关键字导致默认私有成员,而 `struct 关键字导致默认公开成员:
类 X { int a; // X::a 默认是私有的:使用的类
……对……
结构 S { int a; // S::a 默认是公共的:使用的结构体
基类默认可访问性
1.9 还说:
在基类没有访问说明符
public
的情况下,当派生类使用 class-key 定义时假定,并且在使用class-keystruct
定义类private
时假定。class
需要一致使用结构或类的情况......
有一个要求:
在类模板的重新声明、部分特化、显式特化或显式实例化中,类键应与原始类模板声明(9.2.8.3)在种类上一致。
...在任何详细的类型说明符中,
enum
关键字应用于指代枚举(9.7.1),union
类键应用于指代union
(11.5),class
或struct
类键应用于指代非联合类(11.1)。
提供了以下示例(不需要一致性时):
结构 S { } s; 类 S* p = &s; // 好的
尽管如此,一些编译器可能会对此提出警告。
有趣的是,虽然您使用和创建struct
的类型都称为“类”,但我们有...class
union
标准布局结构是使用 class-key 或 class-key 定义的标准
struct
布局类class
。
...所以在标准语言中,当谈到标准布局结构时,它使用“结构”来暗示“不是联合”。
我很好奇在其他术语中是否有类似的“结构”使用,但是对标准进行详尽的搜索是一项太大的工作。欢迎评论。
经过多年使用我的主要语言 C++ 进行编程,我得出一个死结论,即这是 C++ 的另一个愚蠢特性。
两者之间没有真正的区别,也没有理由我应该花额外的时间来决定我应该将我的实体定义为结构还是类。
要回答这个问题,请随时将您的实体定义为结构。默认情况下,成员将是公开的,这是常态。但更重要的是,默认情况下继承是公开的。受保护的继承,甚至更糟糕的是私有继承,都是例外。
我从来没有遇到过私人继承是正确做法的案例。是的,我试图发明使用私有继承的问题,但没有奏效。而Java,如果不使用访问器关键字,面向对象编程的角色模型默认为公共继承。顺便说一句,Java 不允许在继承类上使用访问器关键字,它们只能被公开继承。所以你可以看到,cpp团队真的在这里倒下了。
另一个令人沮丧的事情是,如果你定义为一个类并声明为一个结构,你会收到编译警告。好像这会影响程序的性能或准确性。一个答案还指出,MSVC 可能会传播编译器错误。
那些在下雨时使用课程,在阳光下使用结构的人是根据他们所教的内容这样做的。他们发现这不是真的。Java 没有一对类的名称,只有 class 关键字。如果你想要一个数据结构,只需将所有成员公开,不要添加函数。这在 Java 中有效,我没有看到任何问题。有什么问题?您需要 4 或 5 个 BOM 代码字符来确定如何解释类实体的上下文。
从技术上讲,两者在 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?
我struct
在定义functors
and时使用POD
。否则我使用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; }
};
当我需要创建 POD 类型或仿函数时,我会使用结构。
默认情况下,所有类成员都是私有的,默认情况下所有结构成员都是公共的。类具有默认的私有基础,而 Struct 具有默认的公共基础。在 C 的情况下,结构不能具有成员函数,而在 C++ 的情况下,我们可以将成员函数添加到结构中。除了这些差异之外,我没有发现任何令人惊讶的地方。
仅当我需要保存一些数据而没有任何关联的成员函数(对成员数据进行操作)并直接访问数据变量时,我才使用 struct。
例如:从文件和套接字流等读取/写入数据。在函数参数太多且函数语法看起来太冗长的结构中传递函数参数。
从技术上讲,除了默认可访问性之外,类和结构之间没有太大区别。更重要的是,它取决于您如何使用它的编程风格。
我认为 Structs 旨在作为一种数据结构(如信息的多数据类型数组),而类则用于代码打包(如子例程和函数的集合)。
:(
我从不在 C++ 中使用“结构”。
我无法想象当你想要私有成员时你会使用结构的场景,除非你故意试图混淆。
似乎使用结构更多地是对如何使用数据的句法指示,但我宁愿只创建一个类并尝试以类的名称或通过注释来明确说明。
例如
class PublicInputData {
//data members
};