Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/153.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;构造函数:在初始化器列表之前初始化局部变量_C++ - Fatal编程技术网

C++ C++;构造函数:在初始化器列表之前初始化局部变量

C++ C++;构造函数:在初始化器列表之前初始化局部变量,c++,C++,如何在构造函数(堆栈上)中存储初始值设定项列表所需的临时状态 例如,实现此构造函数 // configabstraction.h #include <istream> class ConfigAbstraction { public: ConfigAbstraction(std::istream& input); private: int m_x; int m_y; int m_z; }; 那么为什么不简单地在构造函数的主体中进行赋值呢

如何在构造函数(堆栈上)中存储初始值设定项列表所需的临时状态

例如,实现此构造函数

// configabstraction.h
#include <istream>

class ConfigAbstraction
{
public:
    ConfigAbstraction(std::istream& input);

private:
    int m_x;
    int m_y;
    int m_z;
};

那么为什么不简单地在构造函数的主体中进行赋值呢

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++!


这不是人为的限制。局部变量的初始化应该如何在其函数范围之外进行?这只会导致很大的混乱,变量实际上是初始化的(命名冲突除外)。

解决问题的另一种方法是将三个独立的
int
s打包到一个公共数据结构中。这将允许您使用私有静态助手函数初始化该类型的对象。能够初始化对象而不是稍后分配给它也允许它是
const
(如果需要)

下面是一个使用
std::tuple
的示例。但是您也可以创建自己的helper
struct
甚至
std::array
;基本思想保持不变:有一个成员对象而不是三个。

#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))
{
}
#包括
#包括
类mysillyparserdont
{
公众:
mysillyparserdontproiser(std::istream&input){/*…*/}
int intByName(const char*name)const{return/*…*/0;}
};
类配置抽象
{
公众:
配置抽象(std::istream&input);
私人:
静态std::元组分析(std::istream&input)
{
std::元组结果;
mysillyparserdont解析器(输入);
std::get(result)=parser.intByName(“a”);
std::get(result)=parser.intByName(“b”);
std::get(result)=parser.intByName(“c”);
返回结果;
}
std::元组常数m;
};
ConfigAbstraction::ConfigAbstraction(std::istream&input)
:m(解析(输入))
{
}

使用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}}
{
}

不能在成员之前初始化局部变量。原因很简单(因此这不是人为的限制):

必须在构造函数体开始之前初始化(构造)成员,因为构造函数体可能会访问它们,并且需要为此访问对它们进行初始化。另一方面,在代码进入构造函数体之前,局部变量不存在(对于任何其他函数)。
结论-在成员之前初始化局部变量是不可能的。

将其作为成员变量?您不在构造函数主体中分配变量有什么原因吗?@NathanOliver:您不能在主体中初始化它们。您只能在那里分配它们。这在本例中是可能的,但如果成员是
const
@ChristianHackl-Oops,则不可能。修正了我的注释,而不是初始化。“什么是C++的人工限制!”——这个“人工限制”存在于我所知道的每种编程语言中(除了那些最初没有使用构造函数的自定义类型的那些)。它似乎不会阻止任何人编写好的、有效的和可读的代码。您可能希望将另一个构造函数设置为私有的。@ChristianHackl是的,我考虑过,但在本例中,有人可能希望直接调用它似乎是合理的。这很有趣。。。我认为这会使类更难使用,因为它迫使用户做出后果难以理解的选择。@ChristianHackl true,我可以选择任何一种方式,所以我做了你建议的编辑。“这只会导致很大的混乱,变量实际上是初始化的。”-欢迎来到编写糟糕的Java构造函数的世界:)@ChristianHackl好吧,编写糟糕的代码就是糟糕的。Java真的编译了这些东西并抛出运行时异常吗?我对Java不太熟悉。在Java中,您可以编写一个类,如
classx{private final int I;X(){int j=1;I=j;}}
。编译器甚至不允许在初始化(或“赋值”)之前使用
i
。它是100%安全和正确的,但我个人认为这是一个相当混乱的功能。也许这也是我的C++背景。如果初始化器可以省略,就在这种情况下,只有普通的旧数据成员,我想是的。但它们通常是无法避免的;我相信编译器会潜入初始值设定项列表中遗漏的任何默认构造函数。我更新了这个问题,以便使用初始值设定项列表是目标的一部分。我相信在执行初始值设定项列表的代码之前,会分配局部变量的内存。我称之为人工,C++阻止使用此代码来实现这个目的。
#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))
{
}
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}}
{
}