C++ 还有一个C++;对象初始化询问

C++ 还有一个C++;对象初始化询问,c++,initialization,initializer-list,C++,Initialization,Initializer List,我有一个类,它有许多类成员和许多不同的构造函数 直到现在,我在我拥有的每个构造函数中都使用了一个构造函数初始化列表,按照我想要的方式对每个成员进行调优 这相当乏味,因为每次我向类中添加新成员时,我都必须访问每个构造函数并更新初始化列表以向该成员添加默认值 所以,我想我应该添加一个方法来初始化我需要的值问题!由于该方法在初始化列表之后执行,因此我在该init列表中输入的特定值将被我的方法覆盖 快速示例: class A { public: A(); A( B b ); A( int i

我有一个类,它有许多类成员和许多不同的构造函数

直到现在,我在我拥有的每个构造函数中都使用了一个构造函数初始化列表,按照我想要的方式对每个成员进行调优

这相当乏味,因为每次我向类中添加新成员时,我都必须访问每个构造函数并更新初始化列表以向该成员添加默认值

所以,我想我应该添加一个方法来初始化我需要的值问题!由于该方法在初始化列表之后执行,因此我在该init列表中输入的特定值将被我的方法覆盖

快速示例:

class A
{
public:
  A();
  A( B b );
  A( int i );
  // A( .... ); plenty of them


private:
  int member1, m2, m3,m4;
  bool b1,b2, b3;
  // ....
  // every time I add a member I have to modify the initialization lists

  // solution: agregate member initialization in a member function: 
  void init_members();    
}

// init list constructors
A::A() : m1(false), m2(false), m3(false), m4(true) .... // looong list
{
}

A::A( B b) : m1(b.state()), m2(false), m3(false), ... // loong list
{
}

// problem, if I use init_members:
void A::init_members()
{
  m1 = false;
  m2 = false;
  m3 = false;
// ...
}

A::A( int i ) : m1( true)
{
  init_members(); // overrides m1 !!!
}
那么,我的问题是:我可以混合使用列表初始值设定项和方法初始值设定项吗,这样列表初始值设定项就可以优先于方法初始值设定项了?
在上面的示例中,我希望m1在最后一个构造函数中保持
true

A::A(int a,int b,double c) : a(a), b(b), c(c) {}
A::A(int a,int b) : a(a), b(b) {} // member c is automatically initialized to 1.0
A::A(double c) : c(c) {} // members a and be are automatically initialized to 1 and 2
A::A() {}; // all members are initialized with their in-class values.
注意:我知道我可以在方法调用之后移动初始化列表,但这意味着我将为成员分配两次值:一次在
init_members()
中,然后在构造函数中重写它。不够理想:-)


我希望有一些小技巧,如果你有库存的话。

对于这样的情况,我不使用基/成员初始值设定项列表(成员在构造函数中的那个点上有“垃圾”或“默认构造函数”值),我使用
init(
函数(从构造函数体调用)。然后,构造函数调用
init_389;()
函数,并且只有一个维护点

类似地,我的
clear()
函数也将调用
init_389;()
函数,以获得“默认”值的单个维护点

就你的情况而言,应该是:

A::A(void)
//...no Base/Member-Initializer list...
{
  init_members();
}

A::clear(void)
{
  init_members();
}
…和覆盖:

A::A(int override_m1)
{
  init_members();
  m1 = override_m1;
}

对于这样的情况,我不使用基/成员初始值设定项列表(成员在构造函数中的该点上具有“垃圾”或“默认构造函数”值),我使用
init\uz()
函数(从构造函数体调用)。然后,构造函数调用
init_389;()
函数,并且只有一个维护点

类似地,我的
clear()
函数也将调用
init_389;()
函数,以获得“默认”值的单个维护点

就你的情况而言,应该是:

A::A(void)
//...no Base/Member-Initializer list...
{
  init_members();
}

A::clear(void)
{
  init_members();
}
…和覆盖:

A::A(int override_m1)
{
  init_members();
  m1 = override_m1;
}

嗯,我不想知道如果你的同事发现这样一个班级,他们会给你起什么名字。。。想象一下,如果他们不得不修复或扩展这种怪物会发生什么。我最近分配了一项任务,将我们代码库中的许多
a
s转换为如下内容:

class AKeyValueStorage {
    // would be some kind of shared storage if meant to be 
    // copyable and don't forget moving if your're on c++11!
    std::map<std::string, boost::any> mMembers;
public:
    template<class Key, class T>
    T const & Get(Key const & pKey) const
    {
        auto tTmp = mMembers.find(ToString(pKey));
        if (tTmp != mMembers.end()) {
            return boost::any_cast<T const &>(*tTmp); 
        }
        // throw if none, or return default
    }

    template<class Key, class T>
    void Set(Key const & pKey, T const & pValue) const
    {
        mMembers[ToString(pKey)] = pValue; // replace if found, insert if none
    }
};
类AkeyValue存储{
//将是某种共享存储(如果有必要的话)
//可复制,如果您使用的是c++11,请不要忘记移动!
std::map mMembers;
公众:
样板
T const&Get(键const&pKey)const
{
auto tTmp=mMembers.find(ToString(pKey));
if(tTmp!=mMembers.end()){
返回升压::任意_投射(*tTmp);
}
//如果无则抛出,或返回默认值
}
样板
无效集(键常量和pKey、T常量和pValue)常量
{
mMembers[ToString(pKey)]=pValue;//如果找到则替换,如果没有则插入
}
};

Hm,我不想知道如果你的同事发现这样的班级,他们会给你起什么名字。。。想象一下,如果他们不得不修复或扩展这种怪物会发生什么。我最近分配了一项任务,将我们代码库中的许多
a
s转换为如下内容:

class AKeyValueStorage {
    // would be some kind of shared storage if meant to be 
    // copyable and don't forget moving if your're on c++11!
    std::map<std::string, boost::any> mMembers;
public:
    template<class Key, class T>
    T const & Get(Key const & pKey) const
    {
        auto tTmp = mMembers.find(ToString(pKey));
        if (tTmp != mMembers.end()) {
            return boost::any_cast<T const &>(*tTmp); 
        }
        // throw if none, or return default
    }

    template<class Key, class T>
    void Set(Key const & pKey, T const & pValue) const
    {
        mMembers[ToString(pKey)] = pValue; // replace if found, insert if none
    }
};
类AkeyValue存储{
//将是某种共享存储(如果有必要的话)
//可复制,如果您使用的是c++11,请不要忘记移动!
std::map mMembers;
公众:
样板
T const&Get(键const&pKey)const
{
auto tTmp=mMembers.find(ToString(pKey));
if(tTmp!=mMembers.end()){
返回升压::任意_投射(*tTmp);
}
//如果无则抛出,或返回默认值
}
样板
无效集(键常量和pKey、T常量和pValue)常量
{
mMembers[ToString(pKey)]=pValue;//如果找到则替换,如果没有则插入
}
};

在C++11中,一个选项可以是构造函数委托,其中一个构造函数只调用另一个构造函数,以避免重复代码

这就是它看起来的样子:

class A {
public:
    A(int,int,double);
    A(int,int);
    A(double);
    A();
private:
    ...
};

A::A(int a,int b,double c) {
    // the real work to initialize the class
}

// A(int,int) delegates to A(int,int,double), passing along a
// default value for the double
A::A(int a,int b) : A(a,b,0.0) {}

A::A(double c) : A(1,2,c) {} // A(double) delegates to A(int,int,double)

A::A() : A(1.0) {} // A() delegates to A(double)
确保不创建任何循环。另外,通常您需要一个构造函数来完成大部分实际工作,而其他构造函数只是封送希望传递给该构造函数的值。我们称之为“指定构造函数”。指定的构造函数应该是接受最多参数且不使用任何默认值的构造函数。最终,所有构造函数都应该直接或间接地调用指定的构造函数

注意这种模式:使用一些默认值的构造函数将这些默认值传递给使用较少默认值的构造函数,直到您到达一个没有任何默认值的函数为止。这与您试图对
init\u members()
方法执行的操作相反。您有一个设置所有默认值的函数,然后尝试覆盖其中一些默认值。如果不能使用C++11特性,最好模拟指定的构造函数模式:
init_members()
将是指定的初始值设定项,并且不会有任何默认值。您可以为每个构造函数使用一个初始值设定项方法,它接受给定的参数,并抛出一些默认值来调用另一个
init_成员
重载

但是,指定的初始值设定项/构造函数的一个问题是,默认值分散在各个地方。C++11中除了委托之外的另一个选项是“类内初始化”,它允许收集所有默认值

class A {
public:
    A(int,int,double);
    A(int,int);
    A(double);
    A();
private:
    int a = 1,b = 2; // in-class initialization gathers all the defaults together
    double c = 1.0;
};
鉴于上述情况,所有施工人员将