首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >又一次C++对象初始化询问

又一次C++对象初始化询问
EN

Stack Overflow用户
提问于 2012-03-28 15:55:31
回答 3查看 534关注 0票数 1

我有一个类,它有很多类成员,还有很多不同的构造函数。

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

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

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

快速示例:

代码语言:javascript
复制
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

注意:我知道我可以在方法调用之后移动初始化列表,但这意味着我会为成员分配两倍的值:一次在init_members()中,然后在构造函数中重写它。不够理想:-)

我希望有个小把戏,如果你有存货的话。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-03-28 17:23:27

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

看上去是这样的:

代码语言:javascript
复制
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_members()方法所做的正好相反。您有一个设置所有默认设置的函数,然后尝试覆盖其中一些默认值。如果您不能使用C++11特性,最好是模拟指定的构造函数模式:init_members()将是您指定的初始化程序,它不会有任何默认值。您可以为每个构造函数使用一个初始化器方法,它接受给定的参数,并添加一些默认值来调用另一个init_members重载。

然而,指定的初始化器/构造函数的一个问题是,缺省值分散在整个地方。除了委托之外,C++11中的另一个选项是“类内初始化”,它允许将所有默认值聚集在一起。

代码语言:javascript
复制
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;
};

在上述情况下,所有构造函数将自动将成员值初始化为这些默认值,除非显式地将其初始化为该构造函数中的其他构造函数。

代码语言:javascript
复制
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()的示例

代码语言:javascript
复制
class A {
public:
    A(int a,int b,double c) { init_members(a,b,c); }
    A(int a,int b) { init_members(a,b); }
    A(double c) {init_members(c);}
    A() { init_members(); }
private:
    void init_members(int,int,double) { ... }
    void init_members(int a,int b) { init_members(a,b,1.0); }
    void init_members(double c) { init_members(1,2,c); }
    void init_members() { init_members(1.0); }
    ...
};

此方法值在调用init_members()之前初始化成员,因此成员被初始化两次。我不确定是否有办法在C++03中解决这个问题。

票数 5
EN

Stack Overflow用户

发布于 2012-03-28 15:58:21

对于这种情况,我不使用Base/ members列表(成员在构造函数的那个点上有“垃圾”或“默认构造函数”值),我使用init_()函数(从构造函数体调用)。然后,构造函数调用init_()函数,并且只有一个维护点。

类似地,我的clear()函数也会为“默认值”的单个维护点调用init_()函数。

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

代码语言:javascript
复制
A::A(void)
//...no Base/Member-Initializer list...
{
  init_members();
}

A::clear(void)
{
  init_members();
}

...and重写:

代码语言:javascript
复制
A::A(int override_m1)
{
  init_members();
  m1 = override_m1;
}
票数 1
EN

Stack Overflow用户

发布于 2012-03-28 16:34:07

嗯,我不想知道如果你的同事发现这样的班级他们会给你什么名字.想象一下,如果他们不得不修复或扩展这类怪物会发生什么。我新分配了一项任务,将我们代码库中的许多A中的一些(变得不可维护)转换为如下内容:

代码语言:javascript
复制
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
    }
};
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9911309

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档