在 C++ 中初始化 C 结构

Posted

技术标签:

【中文标题】在 C++ 中初始化 C 结构【英文标题】:Initialise C-structs in C++ 【发布时间】:2012-01-20 14:22:54 【问题描述】:

我正在创建一堆 C 结构,因此我可以封装要通过 dll c 接口传递的数据。结构有很多成员,我希望它们有默认值,这样就可以只指定几个成员来创建它们。

据我了解,结构需要保持 c 风格,因此不能包含构造函数。创建它们的最佳方法是什么?我在想工厂?

【问题讨论】:

【参考方案1】:
struct Foo 
    static Foo make_default ();
;

工厂是矫枉过正。当您想要创建给定接口的实例时使用它,但实现的运行时类型在创建站点上不是静态已知的。

【讨论】:

工厂吗?尽管是一个函数,而不是一个类型? @dangerousdave:你想要的是一个POD,并且这些都允许有static 成员。 @spraff:那是一个抽象工厂。 拥有一个非抽象的、未封装的“工厂”是没有意义的。它只是添加了毫无意义的行话和OOP-ifying something which is really a function。 @Lightness:我认为“工厂”一词的使用并不一致。它通常像您一样使用,表示任何创建对象的函数或对象。有时它专门用于表示工厂方法模式或抽象工厂模式(我认为两者都有一个带有具体实现的工厂接口,尽管我没有 GoF 书)。将“创造事物的任何事物”定义应用于按值返回的问题在于,它使std::sin 成为工厂——它需要double 并返回一个新创建的double。所以这有点毫无意义。【参考方案2】:

C-Structs 仍然可以有成员函数。但是,如果您开始使用虚函数,就会出现问题,因为这需要在结构内存的某个位置创建一个虚表。普通成员函数(例如构造函数)实际上不会向结构添加任何大小。然后,您可以毫无问题地将结构传递给 DLL。

【讨论】:

@dangerousdave:如果它不起作用,那么我有很多代码会中断。你能提供更多关于你的“实验”的信息吗?对于没有构造函数的结构和有构造函数的结构,你会得到不同的“sizeof”结果吗? 在 C++11 中,这很好,因为它仍然是一个 standard-layout 类(它可以具有构造函数和其他非虚拟成员函数)。在 C++03 中,这在实践中可能没问题,但不能保证添加构造函数会保持布局。 @Mike Seymour:很公平,以前从未听说过(或者更有经验)。您能告诉我规范中涉及该问题的特定部分吗? C++11, 9/6 定义了 standard-layout 类。我手头没有 C++03 的副本,但从记忆中它的“类”一章,可能是第 9 章,没有定义 standard-layout 的概念,只有 吊舱;并且具有构造函数的类不是 POD。 @Mike Seymour:干杯。我对那个感到震惊,tbh,我不知道。我想我很幸运,我遇到过的任何编译器都不会在这样的事情上变得奇怪:D【参考方案3】:

我会使用构造函数类:

struct Foo  ... ;
class MakeFoo

   Foo x;
public:
   MakeFoo(<Required-Members>)
   
     <Initalize Required Members in x>
     <Initalize Members with default values in x>
   

   MakeFoo& optionalMember1(T v)
   
      x.optionalMember1 = v;
   

   // .. for the rest option members;

   operator Foo() const 
   
     return x;
   
;

这允许在表达式中任意设置结构的成员:

processFoo(MakeFoo(1,2,3).optionalMember3(5));

【讨论】:

一个有效的解决方案,但如果你问我这有点过分。有多个语句来构建一个对象有什么问题?链接并不能在使用时节省工作量,它只是在其他地方添加了冗余代码。 @spraff,没有错,但我个人更喜欢面向表达式的接口,不需要包含中间值的变量。【参考方案4】:

我有一个简单的想法,方法如下:

像往常一样制作结构,并创建一个初始化它的简单函数:

struct Foo...;

void Default(Foo &obj) 
    // ... do the initialization here

如果你有多个结构,你可以在 C++ 中重载函数,所以你可以有很多称为“默认”的函数,每个函数都初始化自己的类型,例如:

struct Foo  //... ;
struct Bar  //... ;

void Default(Foo &obj) ...
void Default(Bar &obj) ...

C++ 编译器将根据参数知道何时调用第一个或第二个重载。 & 使 obj 成为对您提供的任何参数的引用,因此对 obj 所做的任何更改都将反映到您作为参数放入的变量中。

编辑: 我对如何指定一些参数也有一个想法,你可以使用默认参数来做到这一点。它是这样工作的:

例如你下面的函数;您可以像这样为参数指定默认值:

void Default (Foo &obj, int number_of_something = 0, int some_other_param = 10)
 ... 

【讨论】:

我有时会使用这种方法。您甚至可以添加额外的参数并使用重载来创建各种构造函数。 默认参数“新”究竟如何?它们总是在标准 C++ 中是有效的,而且我认为在此之前已经有相当长的一段时间了。 你说得对,我最近了解到它们,我假设它们是新的。我做了一些研究,现在我知道了:D

以上是关于在 C++ 中初始化 C 结构的主要内容,如果未能解决你的问题,请参考以下文章

C 编程语言等效于 C++ 中的结构初始化

将带有结构初始化和赋值的 C 代码移动到 c++ 编译器

C++ 结构初始化

如何在 C++ 98 标准结构的初始化列表中初始化 tm struct 成员

C ++使用互斥字段初始化结构

在C ++中初始化一个指向结构的指针数组