另一个C ++对象初始化查询 [英] Yet another C++ Object initialization interrogation

查看:75
本文介绍了另一个C ++对象初始化查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个此类,该类具有许多类成员和许多不同的构造函数.

I have this class that has many class members, and a lot of different constructors.

直到现在,我在每个拥有的构造函数中都使用了一个构造函数初始化列表,以所需的方式调整每个成员.

Until now, I used a constructor initialization list in each of the constructors that I have, tuning each member the way I wanted.

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

This is quite tedious, because everytime I add a new member to my class, I have to visit each constructor and update the initialization list to add a default value to this member.

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

So, I thought I would add a method to initialize the values I need. Problem! Since the method is executed after the initialization list, the particular values I put in this init list are overriden by my method.

快速示例:

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.

So, my question: can I mix list initializer and method initializers, so that list initializers have precedence over the method initializer?
In my example above, I want m1 to stay true for the last constructor.

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

Note: I know I could move the initialization list after the method call, but this means I'd assign twice the values to the members : once in init_members(), then overriding it in the constructor. Not optimal enough :-)

如果您有库存,我希望有一些小技巧.

I was hoping for some little trick, if you have that in stock.

推荐答案

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

In C++11 one option could be constructor delegation, where one constructor simply calls one of the other constructors, so as to avoid duplicating code.

这是它的样子:

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)

确保不创建任何循环.通常,您通常还希望一个构造函数完成大部分实际工作,而其他构造函数仅编组要传递给该构造函数的值.我们将其称为指定的构造函数".指定的构造函数应该是采用最多参数且不使用任何默认值的构造函数.最终,所有构造函数都应直接或间接调用指定的构造函数.

Make sure you don't create any loops. Also typically you'll want a single constructor to do most of the real work while the others just marshal the values they want to pass to that constructor. We'll call this the 'designated constructor'. The designated constructor should be the one that takes the most parameters and doesn't use any default values. Eventually all the constructors should call the designated constructor, directly or indirectly.

请注意模式:使用某些默认值的构造函数会将这些默认值传递给使用较少默认值的构造函数,直到您到达完全没有默认值的函数为止.这与您尝试使用init_members()方法进行的操作相反.您可以使用一个函数来设置所有默认值,然后尝试覆盖其中一些默认值.如果不能使用C ++ 11功能,最好模拟指定的构造函数模式:init_members()将是您指定的初始化程序,并且没有任何默认值.您可以为每个构造函数使用一个初始化程序方法,该方法采用给定的参数,并抛出一些默认值以调用另一个init_members重载.

Note the pattern: constructors that use some default values pass those defaults along to constructors that use fewer defaults, until you arrive at the function with no defaults at all. This is the opposite of what you're trying to do with your init_members() method. You have a function that sets all the defaults, and then you try to override some of them. If you can't use C++11 features, you would be better off emulating the designated constructor pattern: init_members() will be your designated initializer and it will not have any defaults. You can use an initializer method for each constructor which takes the arguments it's given, and throws in a few default values to call another init_members overload.

然而,指定的初始值设定项/构造函数的一个问题是默认值分散在各处. C ++ 11中除委托外的另一个选项是类内初始化",它允许将所有默认值收集在一起.

However one issue with the designated initializer/constructor is that the defaults are scattered all over the place. Another option in C++11 besides delegation is 'in-class initialization', which allows all the default values to be gathered together.

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;
};

鉴于上述情况,除非您将成员值显式初始化为该构造函数中的其他内容,否则所有构造函数都会自动将成员值初始化为那些默认值.

Given the above, all constructors will automatically initialize the member values to those defaults unless you explicitly initialize it to something else in that constructor.

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()的示例:


Here's an example of using init_members():

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中是否有解决此问题的方法.

This method value initializes members before init_members() can be called, so members are initialized twice. I'm not sure there's a way to fix that in C++03.

这篇关于另一个C ++对象初始化查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆