什么时候应该在C++中使用类vs结构?

Ala*_*ffe 895 c++ oop struct ooad class

在什么情况下在C++中使用structvs a 更好class

Com*_*ger 755

C++中a class和a 之间的差异struct是结构具有默认public成员,而基础和类具有默认private成员和基础.两个类和结构可具有的混合物public,protectedprivate构件,可以使用继承并且可以具有成员函数.

我建议使用结构作为普通旧数据结构而不使用任何类类特性,并使用类作为具有private数据和成员函数的聚合数据结构.

  • 没有修饰符或方法的结构称为POD结构,它作为与C库的向后兼容接口存在,因为它(假设)保证布局,就像它是C结构一样.除了这一例外,唯一的区别是如上所述. (90认同)
  • @ workmad3:该名称具有误导性,但9/4(C++ 03)说:"POD结构是一个聚合类,没有非POD结构类型的非静态数据成员,非POD联合(或此类型的数组)或引用,并且没有用户定义的副本赋值运算符,也没有用户定义的析构函数." 使用"struct"类密钥没有限制,对使用"public"没有限制(对于聚合要求,请参见8.5.1/1).这不是"struct"和"class"之间的区别. (26认同)
  • 鉴于标准的定义,您对"聚合"的使用可能会被误解.:) (5认同)
  • 当然,在与C接口时,您可以使用类.类和结构之间没有区别.结构是类; 只有默认访问权限才会从私有转为公共. (4认同)
  • 根据Stroustrup的“原理和实践”书:“结构应主要用于成员可以取任何值的地方”(即,在没有定义有意义的类不变式的地方) (2认同)
  • 这同样适用于默认继承。因此,我更喜欢结构:公共继承 (is-a) 比私有继承 (is-implemented-in-terms-of) 更常见。 (2认同)
  • @mellow-yellow 不幸的是(但不是非常不寻常),Bjarne 的潜在权威人士继续兜售术语中如此糟糕的选择。按照他自己语言的标准,他歪曲了区别!假设这是一个逐字引用,无论如何。 (2认同)

qua*_*ark 215

正如其他人所指出的那样,实际上只存在两种语言差异:

  • struct默认为公共访问,class默认为私人访问.
  • 继承时,struct默认为public继承,class默认为private继承.(具有讽刺意味的是,与C++中的许多内容一样,默认是向后的:public继承是迄今为止更常见的选择,但人们很少声明struct只是为了节省输入" public"关键字.

但在实践中,真正的差别是间class/ struct声明构造函数/析构函数不和的.对于"普通旧数据"POD类型有一定的保证,一旦你接管了类的构造,它就不再适用了.为了清楚地区分这种区别,许多人故意仅将structs用于POD类型,如果他们要添加任何方法,请使用classes.下面两个片段之间的区别是没有意义的:

class X
{
  public:

  // ...
};

struct X
{
  // ...
};
Run Code Online (Sandbox Code Playgroud)

(顺便提一下,这里有一个关于"POD类型"实际含义的一些好解释的线程:C++中的POD类型是什么?)

  • 是否使用`struct`或`class`与您的对象是否为POD或是否应定义复制构造函数/析构函数无关.成员函数也与POD无关.当我重新阅读你所写的内容时,我发现你并不是在暗示,但目前的措辞令人困惑 (7认同)
  • 这个答案的"真正差异"部分是完全错误的. (2认同)

Lig*_*ica 158

现有答案中存在许多误解.

两者classstruct宣布一个班级.

是的,您可能必须在类定义中重新排列访问修改关键字,具体取决于您用于声明类的关键字.

但是,除了语法之外,选择一个而不是另一个的唯一原因是约定/样式/偏好.

有些人喜欢在struct没有成员函数的情况下坚持使用关键字,因为结果定义"看起来像"来自C的简单结构.

类似地,有些人喜欢将class关键字用于具有成员函数和private数据的类,因为它上面写着"类",因此看起来就像他们最喜欢的面向对象编程的书中的例子.

现实情况是,这完全取决于您和您的团队,这对您的计划来说几乎没有任何区别.

除了名称之外,以下两个类在各方面都是完全相同的:

struct Foo
{
   int x;
};

class Bar
{
public:
   int x;
};
Run Code Online (Sandbox Code Playgroud)

您甚至可以在重新声明时切换关键字:

class Foo;
struct Bar;
Run Code Online (Sandbox Code Playgroud)

(尽管由于不符合性而导致Visual Studio构建中断,因此编译器会在您执行此操作时发出警告.)

并且以下表达式都评估为true:

std::is_class<Foo>::value
std::is_class<Bar>::value
Run Code Online (Sandbox Code Playgroud)

但请注意,重新定义时无法切换关键字; 这只是因为(根据单一定义规则)跨翻译单元的重复类定义必须"由相同的标记序列组成".这意味着你甚至无法交流const int member;int const member;,并有无关的语义classstruct.

  • 这是非常翔实的,老实说,我最喜欢的答案.其他人都将它们视为独立的实体,当它们在引擎盖下时,它们是相同的.我想知道Arduino环境中的结构定义是否被认为是cpp类,因为它是使用g ++编译的. (12认同)
  • 因此,如果我理解这一点:只要您的可见性修饰符是明确的,而不是省略,那就无所谓了.你可以编写一个巨大的C++应用程序,只使用结构; 或者您可以通过并将结构的每个案例更改为类.只要您不使用默认可见性,应用程序就会完全相同. (5认同)
  • @Ben当然是.Arduino编译器编译C++; 这就是结束. (3认同)

Fer*_*cio 54

我唯一一次使用struct而不是类是在函数调用中使用它之前声明一个仿函数,并且为了清晰起见希望最小化语法.例如:

struct Compare { bool operator() { ... } };
std::sort(collection.begin(), collection.end(), Compare()); 
Run Code Online (Sandbox Code Playgroud)

  • 现在几年之后,所有主要编译器都支持C++ 11,[Lambdas使这更加简洁](http://stackoverflow.com/a/7627218/439793). (35认同)

Tal*_*man 35

C++ FAQ Lite:

结构的成员和基类默认是公共的,而在类中,它们默认为private.注意:您应该明确公开,私有或保护基类,而不是依赖于默认值.

struct和class在功能上是等价的.

好的,足够的那个干净的技术谈话.在情感上,大多数开发人员在类和结构之间做出了很强的区分.结构只是感觉像一堆开放的位,几乎没有封装或功能.课程感觉像是一个生活和负责任的社会成员,拥有智能服务,强大的封装屏障和明确的界面.既然这是大多数人已经拥有的内涵,那么你应该使用struct关键字,如果你有一个只有很少的方法并且有公共数据的类(这样的东西确实存在于设计良好的系统中!),否则你应该使用这个类关键词.

  • 我不明白为什么他们说结构和类在功能上是相同的,但在某些情况下却说在没有任何推理的情况下更喜欢其中一个。 (3认同)
  • 原因是惯例.编译器不关心您使用哪一个,但另一个查看代码的开发人员将更容易理解您的意思. (3认同)
  • @deetz:整个第三段都是推理。 (3认同)

mby*_*215 22

结构对我有用的一个地方就是我有一个系统从另一个系统接收固定格式的消息(比如说,一个串口).您可以将字节流强制转换为定义字段的结构,然后轻松访问字段.

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);
}
Run Code Online (Sandbox Code Playgroud)

显然,这与你在C中做的一样,但我发现必须将消息解码为类的开销通常是不值得的.

  • 或者你可以在一个类上实现`operator >>`而不是编写`processMessage`函数,这将使你的C++看起来更像正确的C++而不是像C一样. (11认同)
  • 除了它在不同系统之间不可移植的事实之外,这违反了别名规则,因此即使在单个体系结构中也不能保证它可以工作。 (2认同)
  • @jacwah 嗯,好点。别名在这里不会成为问题,因为其中一个指针是“char”类型,可以免除别名。然而,仍然存在一个问题,尽管是一个不同的问题:如果在该地址上实际上没有任何已初始化的后一种类型的对象,则将 char* 转换为不同的类型是 UB,因为它违反了生命周期规则。Afaik,即使目标类型是可简单构造的,仅分配内存也不足以让 C++ 正式允许将该内存视为该类型。 (2认同)

Adi*_*sak 18

如果要编写内部为C++但可以通过C或C++代码调用API的库,则可以在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
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用C++代码在C++文件中编写函数bar(),并使其可以从C调用,并且两个世界可以通过声明的struct共享数据.当然,在混合C和C++时还有其他注意事项,但这是一个简化的例子.

  • 最合适的答案.C兼容性确实是最重要的原因.所有其他的东西,如默认访问是深奥的. (2认同)

ogo*_*oid 15

正如每个人所说,唯一真正的区别是默认访问.但是,当我不想使用简单的数据类进行任何类型的封装时,我特别使用struct,即使我实现了一些辅助方法.例如,当我需要这样的东西时:

struct myvec {
    int x;
    int y;
    int z;

    int length() {return x+y+z;}
};
Run Code Online (Sandbox Code Playgroud)

  • +1 给出了一个带有一些成员函数的结构的例子,这些成员函数并不觉得你已经“带走了结构”。 (2认同)

小智 9

当您使用C++实现提供C兼容接口时,Structs(更一般地说是POD)很方便,因为它们可以跨语言边界和链接器格式移植.

如果你不关心这一点,那么我认为使用"struct"而不是"class"是一个很好的意向沟通者(正如@ZeroSignal所说).结构也具有更可预测的复制语义,因此它们对于您打算写入外部媒体或通过线路发送的数据非常有用.

结构对于各种元编程任务也很方便,比如只显示一堆依赖类型构造的特征模板:

template <typename T> struct type_traits {
  typedef T type;
  typedef T::iterator_type iterator_type;
  ...
};
Run Code Online (Sandbox Code Playgroud)

......但这真的只是利用struct的默认保护级别是公开的......

  • "可预测的复制语义":语义与类相同(并且具有相同的问题(浅拷贝)). (4认同)
  • 这篇文章让你相信(希望偶然)所有的结构都是POD.这根本不是真的.我希望人们不会因此而误导. (2认同)

And*_*ndy 8

对于C++,结构和类之间确实没有太大的区别.主要功能区别在于,默认情况下结构的成员是公共的,而在类中默认是私有的.否则,就语言而言,它们是等价的.

也就是说,我倾向于像在C#中一样使用C++中的结构,类似于Brian所说的.结构是简单的数据容器,而类用于需要对数据执行操作的对象,而不仅仅是保持数据.


Ala*_*ffe 8

回答我自己的问题(无耻地),如前所述,访问权限是C++中它们之间的唯一区别.

我倾向于仅使用结构进行数据存储.如果它更容易处理数据,我将允许它获得一些辅助函数.但是,只要数据需要流控制(即维护或保护内部状态的getter/setter)或开始获取任何主要功能(基本上更像对象),它就会"升级"到类以更好地传达意图.


Ric*_*ers 8

struct尽管可见性的默认值不同,但和两者class在底层是相同的,struct默认是公共的,class默认是私有的。private您可以通过适当使用和将其中一个更改为另一个public。它们都允许继承、方法、构造函数、析构函数以及面向对象语言的所有其他优点。

然而,两者之间的一个巨大区别是,structC 中支持 as 关键字,而 C 中class则不支持。这意味着可以struct在包含文件中使用 a,该包含文件可以是#includeC++ 或 C,只要它struct是纯 C 样式struct并且包含文件中的其他所有内容都与 C 兼容,即没有 C++ 特定关键字,例如privatepublic、 no方法,没有继承等等。

AC 风格可以与其他支持使用 C 风格通过接口来回传送数据的接口一起struct使用。struct

AC 样式struct是一种描述内存区域布局的模板(不是 C++ 模板,而是模式或模板)。多年来,已经创建了可通过 C 语言和 C 插件(这里介绍的是 Java、Python 和 Visual Basic)使用的接口,其中一些接口适用于 C 风格struct


pas*_*sbi 6

正如其他人指出的那样

  • 除了默认可见性之外,两者都是等效的
  • 无论出于何种原因,可能有理由被迫使用一种或另一种

Stroustrup/Sutter 有一个关于何时使用 which 的明确建议:

如果类具有不变量,则使用类;如果数据成员可以独立变化,则使用 struct

但是,请记住,预先声明某事是不明智的。作为类 ( class X;) 并将其定义为 struct ( struct X { ... })。它可能适用于某些链接器(例如,g++),而在其他链接器(例如,MSVC)上可能会失败,因此您会发现自己陷入了开发人员的地狱。

  • 嗯,[VS在这方面似乎不合规](/sf/ask/2343853641/)(见图) (2认同)

eni*_*tic 5

它们几乎是一样的。感谢 C++ 的魔力,结构体可以像类一样保存函数、使用继承、使用“new”创建等等

唯一的功能区别是类以私有访问权限开头,而结构以公共访问权限开头。这是保持与 C 的向后兼容性。

在实践中,我一直使用结构作为数据持有者和类作为对象。


Vor*_*rac 5

structover 的一个优点class是它节省了一行代码,如果坚持“首先是公共成员,然后是私有成员”。从这个角度来看,我发现关键字class没用。

这是使用 onlystruct和 never 的另一个原因class。C++ 的一些代码风格指南建议对函数宏使用小写字母,理由是当宏转换为内联函数时,名称不需要更改。同样在这里。你有一个漂亮的 C 风格结构,有一天,你发现你需要添加一个构造函数,或者一些方便的方法。你把它改成一个class?到处?

区分structs 和classes 太麻烦了,进入了我们应该做的事情的方式——编程。像许多 C++ 的问题一样,它产生于对向后兼容性的强烈渴望。