构造函数初始值设定项列表中的非成员初始化
Non-member initialization in constructor initializer list
困惑?我也是。。。考虑以下
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;
};
上面的操作很好,并初始化构造函数的成员初始化列表中的std::map
。现在考虑一下:
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;
};
注意,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;
}
};
当然,上面的内容不会编译,但在构造函数初始化期间,有没有任何方法可以在其中一个mixin中初始化ThresholdSensor::CommonData
中的映射。即我可以通过引用传递映射,在mixins构造函数中初始化它吗?
基本子对象是在数据成员之前构造的,因此基本初始值设定项通常不能使用派生的数据成员。
我只想保持简单,并有一个正常的成员功能:
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); }
// ^^^^^^^^^^^^^^^^^^^^^
// ...
};
用法:
Thing<Foo> x;
在有问题的构造函数中,thresholds
作为参数传递给构造函数。
初始化器语法用于初始化超类和类成员。对于其他一切,这就是构造函数的主体的作用:
class Bar
{
public:
Bar( Thresholds & thresholds,
const double & _warningThres,
const double & _zeroThres)
{
thresholds=MapInitializer<std::string , double>()
.Add("warning" , _warningThres)
.Add("zero" , _zeroThres)
}
};
在这个例子中没有超类或其他类成员,所以这很好。在您的示例中,我没有看到任何需要在构造函数的初始化部分初始化thresholds
的显式依赖项。
但假设存在。假设thresholds
与超类或类成员之间存在某种依赖关系,由于某些未指定的依赖关系,在初始化其他对象之前,必须先初始化thresholds
。类成员或超类必须在构造函数的初始化部分初始化,所以我们也需要在那里初始化thresholds
。
如果我们用一个具体的例子:,那就容易多了
class Bar
{
public:
Bar( Thresholds & thresholds,
const double & _warningThres,
const double & _zeroThres);
class private_bar {
public:
private_bar(Thresholds &thresholds);
};
private:
private_bar secret;
};
假设Bar
的构造函数需要构造secret
,但只有在初始化thresholds
之后,它才会传递给private_bar
的构造函数。不难想象会发生这种情况。private_bar
的构造函数使用初始化的thresholds
,仅此而已。现在,您已经在Bar
的构造函数的初始化部分初始化了secret
成员,但在此之前需要初始化thresholds
。我相信这就是你的问题。
在这种情况下,解决方案通常采用以下通用设计模式:
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;
};
这就是为什么"可以在类的构造函数列表中进行非成员初始化",以回答您的问题。如果真的有必要这样做,那一定是因为else需要首先在构造函数列表中初始化。否则,您可以简单地在构造函数主体中初始化它。
但是,如果需要在构造函数列表中初始化其他东西,那么您只需在该构造的顶部"背负",以便使用辅助函数初始化非成员对象。
- C++成员初始化
- c++构造函数成员初始化:传递参数
- C++正确的指针成员初始化
- 将另一个类的对象传递到当前类C++的构造函数中(不是成员初始化)
- WinLamb 错误:成员初始化非法
- 使用其他成员初始化结构的成员?
- C++模板类静态成员初始化
- 解释了构造函数成员初始化列表
- 如何在成员初始化列表中声明共享指针
- C++入门5版:使用get成员初始化另一个与shared_ptr无关的对象
- C++11 默认类成员初始化与初始值设定项列表同时
- 调用非默认构造函数作为成员初始化
- C++模板成员初始化:用右值移动构造,但用左值移动引用
- 类成员初始化C++
- 在成员初始化列表中,我可以创建对列表中不在列表中的成员变量的引用
- C :(不重复)积分静态成员初始化(不仅是声明!),导致链接器错误,原因
- 如何调用成员初始化器列表中参考成员的构造函数
- C 构造函数采用成员初始化器
- 与其他静态const成员初始化静态常量成员
- 静态内联成员初始化顺序