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

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

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

【问题讨论】:

    标签: c++ c dll struct


    【解决方案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
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多