简体   繁体   English

构造函数初始化列表中的非成员初始化

[英]Non-member initialization in constructor initializer list

Confused? 困惑? Me too... Consider the following 我也是......考虑以下几点

typedef std::map<std::string , double> Thresholds;

class Foo 
{
    public: 
        Foo( const double & _toxicThres , const double & _zeroThres )
    : thresholds
    (
        MapInitializer<std::string , double>()
            .Add("toxic" , _toxicThres)
            .Add("zero" , _zeroThres)
    )

    private:
       Thresholds thresholds; 
};

The above works fine and initializes an std::map in the constructor's member initialisation list. 上面的工作正常,并在构造函数的成员初始化列表中初始化std::map Now consider this: 现在考虑一下:

typedef std::map<std::string , double> Thresholds;
struct CommonData
{
    Thresholds thresholds;
};

class Foo //a mixin
{
    public: 
        Foo( Thresholds & thresholds , const double & _toxicThres , const double & _zeroThres )
    : thresholds
    (
        MapInitializer<std::string , double>()
            .Add("toxic" , _toxicThres)
            .Add("zero" , _zeroThres)
    )
};

class Bar //another mixin
{
    public: 
        Bar( Thresholds & thresholds , const double & _warningThres , const double & _zeroThres)
    : thresholds
    (
        MapInitializer<std::string , double>()
            .Add("warning" , _warningThres)
            .Add("zero" , _zeroThres)
    )
};

class OtherGasThreshold{/*...*/}; //yet another mixin, etc...

template<typename ThresholdMixin> //Foo , Bar , or others ...
class ThresholdSensor : public ThresholdMixin 
{
    public:
        ThresholdSensor(double val1 , double val2) 
            : ThresholdMixin(cd.thresholds, val1 , val2)
        {}

    private:
        CommonData cd;
};

Note that the MapIniializer code comes from here , and is 请注意, MapIniializer代码来自此处 ,并且是

template<class K, class V>
class MapInitializer
{
    std::map<K,V> m;
public:
    operator std::map<K,V>() const 
    { 
        return m; 
    }

    MapInitializer& Add( const K& k, const V& v )
    {
        m[ k ] = v;
        return *this;
    }
};

Of course the above would not compile, but is there any way to init the map in ThresholdSensor::CommonData in one of the mixins during constructor init. 当然以上都不会编译,但是有没有办法在构造函数init期间在其中一个mixin中的ThresholdSensor::CommonData中初始化地图。 ie can I pass by reference the map, init it in the mixins constructor? 即我可以通过引用传递地图,在mixins构造函数中初始化它吗?

The base subobjects are constructed before the data members, so generally a base initializer can't use derived data members. 基础子对象在数据成员之前构造,因此通常基本初始化程序不能使用派生数据成员。

I would just keep it simple and have a normal member function: 我会保持简单并具有正常的成员函数:

struct Foo
{
    void Init(Thresholds & thresholds)
    {
         thresholds.emplace("foo", 1.0);
         thresholds.emplace("bar", 1.5);
    }

    // ...
};

template <typename Mx>
struct Thing : Mx
{
    Thresholds thresholds;

    Thing() { Mx::Init(thresholds); }
    //        ^^^^^^^^^^^^^^^^^^^^^

    // ...
};

Usage: 用法:

Thing<Foo> x;

In the constructor in question, thresholds gets passed as a parameter to the constructor. 在有问题的构造函数中, thresholds作为参数传递给构造函数。

The initializer syntax is for initializing superclasses, and class members. 初始化语法用于初始化超类和类成员。 For everything else, that's what the constructor's body is for: 对于其他一切,这就是构造函数的主体:

class Bar
{
    public: 
        Bar( Thresholds & thresholds,
             const double & _warningThres,
             const double & _zeroThres)
    {
       thresholds=MapInitializer<std::string , double>()
            .Add("warning" , _warningThres)
            .Add("zero" , _zeroThres)
    }
};

There are no superclasses or other class members in this example, so this works fine. 在这个例子中没有超类或其他类成员,所以这很好。 I do not see any explicit dependency in your example that requires thresholds to be initialized in the initialization section of the constructor. 我没有在您的示例中看到任何需要在构造函数的初始化部分初始化thresholds显式依赖项。

But suppose there is. 但是假设有。 Let's say there was a dependency of some sort between thresholds , and either the superclass, or a class member, and due to some unspecified dependency it becomes necessary to initialize thresholds first, before initializing the other object. 假设在thresholds与超类或类成员之间存在某种依赖关系,并且由于某些未指定的依赖关系,在初始化其他对象之前,首先需要初始化thresholds The class member, or the superclass must be initialized in the initialization section of the constructor, so we need to initialize thresholds there, too. 必须在构造函数的初始化部分初始化类成员或超类,因此我们也需要在那里初始化thresholds

It's much easier if we use a concrete example: 如果我们使用一个具体的例子,那就容易多了:

class Bar
{
    public: 
        Bar( Thresholds & thresholds,
             const double & _warningThres,
             const double & _zeroThres);

    class private_bar {
    public:
         private_bar(Thresholds &thresholds);
    };

private:
    private_bar secret;
};

Let's say that Bar 's constructor needs to construct secret but only after initializing thresholds , that gets passed to private_bar 's constructor. 假设Bar的构造函数需要构造secret但只有在初始化thresholds之后才会传递给private_bar的构造函数。 It's not hard to imagine a situation where this happens. 不难想象出现这种情况的情况。 private_bar 's constructor uses an initialized thresholds , and that's that. private_bar的构造函数使用初始化的thresholds ,就是这样。 Now, you have initialize the secret member in the initialization section of Bar 's constructor, but thresholds needs to be initialized before this happens. 现在,您已经在Bar的构造函数的初始化部分初始化了secret成员,但是在此之前需要初始化thresholds I believe that this is what your question boils down to. 我相信这就是你的问题归结为。

In this situation the solution typically takes the following generic design pattern: 在这种情况下,解决方案通常采用以下通用设计模式:

class Bar
{

       static Thresholds &init_thresholds(Thresholds &thresholds)
       {
          thresholds=MapInitializer<std::string , double>()
            .Add("warning" , _warningThres)
            .Add("zero" , _zeroThres)

          return thresholds;
       }

    public: 
        Bar( Thresholds & thresholds,
             const double & _warningThres,
             const double & _zeroThres)
             : secret(init_thresholds(thresholds))
        {
        }

    class private_bar {
    public:
         private_bar(Thresholds &thresholds);
    };

private:
    private_bar secret;
};

And that's how it's "possible to do non-member initialization in the constructor list of a class", to answer your question. 这就是“可以在类的构造函数列表中进行非成员初始化”,以回答您的问题。 If it is truly necessary to do that, it must be because something else needs to be initialized in the constructor list, first. 如果真的有必要这样做,那一定是因为首先需要在构造函数列表中初始化其他东西。 Otherwise you can simply initialize it in the main constructor body. 否则,您只需在主构造函数体中初始化它。

But if something else needs to be initialized in the constructor list, then you just "piggy-back" on top of that construction, in order to initialize your non-member object, using a helper function. 但是如果需要在构造函数列表中初始化其他东西,那么你只需要“捎带”在该构造之上,以便使用辅助函数初始化非成员对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 具有 std::initializer_list 参数的非成员函数(/非构造函数上下文)的重载解析 - Overload resolution for non-member functions (/non-constructor contexts) with std::initializer_list argument(s) c2797成员初始化程序列表中的列表初始化或未实现的非静态数据成员初始化程序 - c2797 List initialization inside member initializer list or non static data member initializer not implemented C ++和C非成员多结构初始化 - C++ and C non-member multiple structs initialization 通过C ++中的构造函数初始化器列表进行私有成员数组初始化 - private member array initialization through constructor initializer's list in c++ 每个构造函数成员初始化器列表的 const 数据成员的初始化,错误:没有匹配的 function 用于调用 - Initialization of const data members per constructor member-initializer list, error: no matching function for call 成员初始化器列表,不带参数的指针初始化 - Member initializer list, pointer initialization without argument 成员初始化列表错误的统一初始化 - Uniform initialization on member initializer list error 初始化列表中const引用成员的初始化 - Initialization of const reference member in initializer list 使用std :: initializer_list显式构造函数和初始化 - Explicit constructor and initialization with std::initializer_list C++链表非成员函数反向打印 - C++Linked list non-member function to reverse print
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM