正确的方式有条件地初始化一个C ++成员变量?(Right way to conditionally

2019-06-23 14:44发布

我敢肯定,这是一个非常简单的问题。 下面的代码显示了我想要做的事:

class MemberClass {
public:
    MemberClass(int abc){ }
};

class MyClass {
public:
    MemberClass m_class;
    MyClass(int xyz) {
        if(xyz == 42)
            m_class = MemberClass(12);
        else
            m_class = MemberClass(32);
    }
};

这不编译,因为m_class正在用一个空的构造(不存在)创建。 什么是这样做的正确方法吗? 我的猜测是使用指针和实例m_class使用new ,但我希望有一个更简单的方法。

编辑:我刚才已说过,但我的实际问题有一个额外的复杂性:我需要初始化m_class之前调用的方法,以建立环境。 所以:

class MyClass {
public:
    MemberClass m_class;
    MyClass(int xyz) {
        do_something(); // this must happen before m_class is created
        if(xyz == 42)
            m_class = MemberClass(12);
        else
            m_class = MemberClass(32);
    }
};

是否有可能与花哨的初始化列表技巧来实现这一目标?

Answer 1:

使用条件运算符。 如果表达式较大,使用函数

class MyClass {
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(xyz == 42 ? 12 : 32) {

    }
};

class MyClass {
    static int classInit(int n) { ... }
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(classInit(xyz)) {

    }
};

要初始化m_class之前调用一个函数,你可以把该成员和杠杆RAII前一个struct

class MyClass {
    static int classInit(int n) { ... }
    struct EnvironmentInitializer {
        EnvironmentInitializer() {
            do_something();
        }
    } env_initializer;
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(classInit(xyz)) {

    }
};

这将调用do_something()初始化之前m_class 。 请注意,你不能调用非静态成员函数MyClass构造函数初始化列表完成之前。 该功能必须是它的基类的成员,基类的构造函数必须已完成该工作。

还要注意的是功能,当然,总是叫,为每个创建单独的对象 - 不仅为创建的第一个对象。 如果你想这样做,你可以创建初始化的构造函数内的静态变量:

class MyClass {
    static int classInit(int n) { ... }
    struct EnvironmentInitializer {
        EnvironmentInitializer() {
            static int only_once = (do_something(), 0);
        }
    } env_initializer;
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(classInit(xyz)) {

    }
};

它使用逗号操作符。 请注意,您可以通过赶上抛出的异常do_something使用功能try块

class MyClass {
    static int classInit(int n) { ... }
    struct EnvironmentInitializer {
        EnvironmentInitializer() {
            static int only_once = (do_something(), 0);
        }
    } env_initializer;
public:
    MemberClass m_class;
    MyClass(int xyz) try : m_class(classInit(xyz)) {

    } catch(...) { /* handle exception */ }
};

do_something功能将再次下一次调用,如果把它扔到引起的那个异常MyClass对象不能被创建。 希望这可以帮助 :)



Answer 2:

使用初始化列表语法:

class MyClass {
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(xyz == 42 ? MemberClass(12) : MemberClass(32)
                               /* see the comments, cleaner as xyz == 42 ? 12 : 32*/)
    { }
};

也许吸尘器工厂:

MemberClass create_member(int x){
   if(xyz == 42)
     return MemberClass(12);
    // ...
}

//...
 MyClass(int xyz) : m_class(create_member(xyz))


Answer 3:

 MyClass(int xyz) : m_class(xyz==42 ? 12 : 32) {}

要回答你的修订问题,即变得有点棘手。 最简单的方法是使m_class的指针。 如果你真的想把它当作一个数据成员,那么你必须得到创造性。 创建一个新的类(如果它定义内部MyClass的是最好的)。 有它的构造函数是需要被调用的函数。 第一个数据成员的声明(这将使其第一instaniated)中包含它。

class MyClass 
{
     class initer { public: initer() {
                    // this must happen before m_class is created
                    do_something();                        
                    }
                   }

    initer     dummy;
public:

    MemberClass m_class;
    MyClass(int xyz) : m_class(xyz==42? 12 : 43)
    {
        // dummy silently default ctor'ed before m_class.
    }
};


Answer 4:

要么:

class MemberClass {
public:
    MemberClass(int abc){ }
};

class MyClass {
public:
    MemberClass* m_class;
    MyClass(int xyz) {
        if(xyz == 42)
            m_class = new MemberClass(12);
        else
            m_class = new MemberClass(32);
    }
};

如果你不知何故仍然要保持相同的语法。 会员initalization是更有效的,但。



Answer 5:

试试这个:

class MemberClass
{
public:    
   MemberClass(int abc = 0){ }
};

这使得它的默认值,并且您的默认构造函数。



Answer 6:

有初始化发生其他的事情发生后,你确实需要使用指针,是这样的:

class MyClass {
public:
    MemberClass * m_pClass;
    MyClass(int xyz) {
        do_something(); // this must happen before m_class is created
        if(xyz == 42)
            m_pClass = new MemberClass(12);
        else
            m_pClass = new MemberClass(32);
    }
};

唯一的区别是,你需要访问成员变量m_pClass->counter ,而不是m_class.counter ,并delete m_pClass在析构函数。



文章来源: Right way to conditionally initialize a C++ member variable?