如何在构造函数(堆栈中)中存储初始化列表所需的临时状态?
例如,实现此构造函数......
// configabstraction.h
#include <istream>
class ConfigAbstraction
{
public:
ConfigAbstraction(std::istream& input);
private:
int m_x;
int m_y;
int m_z;
};
...使用像这样的有状态助手类?
// mysillyparserdontworry.h
#include <json/reader.h> //jsoncpp
class MySillyParserDontWorry
{
public:
MySillyParserDontWorry(std::istream& input) { input >> m_parseTree; }
int intByName(const char* name) const { return m_parseTree[name].asInt(); }
private:
Json::Value m_parseTree;
};
我的尝试:
// configabstraction.cpp
ConfigAbstraction::ConfigAbstraction(std::istream& input)
: local_parserState(input) // init local variable first: Not possible!
, m_a(local_parserState.intByName("a"))
, m_b(local_parserState.intByName("b"))
, m_c(local_parserState.intByName("c"))
{
MySillyParserDontWorry local_parserState; // ...because it is local
}
C ++的人为限制!
答案 0 :(得分:5)
使用C ++ 11,您可以通过委派构造函数来解决这个问题:
class ConfigAbstraction
{
public:
ConfigAbstraction(std::istream& input);
private:
ConfigAbstraction(const MySillyParserDontWorry& parser);
int m_a;
int m_b;
int m_c;
};
ConfigAbstraction::ConfigAbstraction(const MySillyParserDontWorry& parser)
: m_a{parser.intByName("a")}
, m_b{parser.intByName("b")}
, m_c{parser.intByName("c")}
{
}
ConfigAbstraction::ConfigAbstraction(std::istream& input)
: ConfigAbstraction{MySillyParserDontWorry{input}}
{
}
答案 1 :(得分:1)
为什么不简单地在构造函数的主体中进行赋值呢?
ConfigAbstraction::ConfigAbstraction(std::istream& input)
: m_a(0)
, m_b(0)
, m_c(0)
{
MySillyParserDontWorry local_parserState;
m_a = local_parserState.intByName("a");
m_b = local_parserState.intByName("b");
m_c = local_parserState.intByName("c");
}
是否有任何特定要求阻碍您这样做?
C ++的人为限制!
这不是人为限制。如何在函数范围之外完成局部变量的初始化?它只会导致很大的混乱,其中变量实际上是初始化的(除了命名冲突)。
答案 2 :(得分:0)
解决问题的另一种方法是将三个int
打包成一个公共数据结构。这将允许您使用私有静态帮助程序函数初始化该类型的对象。能够初始化对象而不是稍后分配对象也允许它为const
(如果需要)。
以下是std::tuple
的示例。但您也可以创建自己的助手struct
甚至std::array<int, 3>
;基本思想保持不变:有一个成员对象而不是三个。
#include <istream>
#include <tuple>
class MySillyParserDontWorry
{
public:
MySillyParserDontWorry(std::istream& input) { /* ... */ }
int intByName(const char* name) const { return /* ... */ 0; }
};
class ConfigAbstraction
{
public:
ConfigAbstraction(std::istream& input);
private:
static std::tuple<int, int, int> parse(std::istream& input)
{
std::tuple<int, int, int> result;
MySillyParserDontWorry parser(input);
std::get<0>(result) = parser.intByName("a");
std::get<1>(result) = parser.intByName("b");
std::get<2>(result) = parser.intByName("c");
return result;
}
std::tuple<int, int, int> const m;
};
ConfigAbstraction::ConfigAbstraction(std::istream& input)
: m(parse(input))
{
}
答案 3 :(得分:0)
您无法在成员之前初始化局部变量。原因很简单(因此它不是人为的限制):
必须在构造函数体开始之前初始化(构造)成员,因为构造函数体可能会访问它们 - 并且需要为此访问初始化它们。另一方面,在代码进入构造函数体之前,局部变量不存在(与任何其他函数一样)。 结论 - 在成员之前初始化局部变量是不可能的。