C++ 有条件地初始化C++;成员变量?

C++ 有条件地初始化C++;成员变量?,c++,class,member-initialization,C++,Class,Member Initialization,我相信这是一个非常简单的问题。以下代码显示了我正在尝试执行的操作: class MemberClass { public: MemberClass(int abc){ } }; class MyClass { public: MemberClass m_class; MyClass(int xyz) { if(xyz == 42) m_class = MemberClass(12); else

我相信这是一个非常简单的问题。以下代码显示了我正在尝试执行的操作:

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_类
。正确的做法是什么?我的猜测是使用指针并使用
new
实例化
m_类,但我希望有一种更简单的方法

编辑:我应该在前面说,但我的实际问题还有一个额外的复杂性:我需要在初始化m_类之前调用一个方法,以便设置环境。因此:

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

使用奇特的初始化列表技巧可以实现这一点吗?

使用初始化列表语法:

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))
为了回答你修改过的问题,这有点棘手。最简单的方法是使
m_class
成为指针。如果你真的想让它成为一个数据成员,那么你必须要有创意。创建一个新类(最好是在MyClass内部定义)。让它成为需要调用的函数。首先将其包含在数据成员声明中(这将使其成为第一个实例)


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

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_类之前调用函数,可以在该成员之前放置一个结构并利用RAII

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)) {

    }
};
这将在初始化
m\u类之前调用
do\u something()
。请注意,在构造函数初始值设定项列表完成之前,不允许调用
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)) {

    }
};
它使用逗号运算符。请注意,通过使用函数try块,您可以捕获由
do\u something
引发的任何异常

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 */ }
};
如果
dou\u something
函数抛出导致
MyClass
对象无法创建的异常,则下次将再次调用该函数。希望这有帮助:)

或者:

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);
    }
};
如果您仍然想保持相同的语法。不过,成员初始化更有效。

试试以下方法:

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

这将为它提供一个默认值和默认构造函数。

要在其他事情发生后进行初始化,确实需要使用指针,如下所示:

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
,以及
在析构函数中删除m_pClass

您正在创建一个未命名的对象,然后使用复制构造函数初始化成员,而不是直接初始化它。是的,打字太快了,对我自己也不好。就我个人而言,我仍然会将逻辑移到MemberClass或factory中。有时,没有默认构造函数是有原因的。您必须有一个默认参数将其置于某种已知的僵尸状态。不理想,但有时是唯一的方法。有时有理由将默认构造函数设置为私有,但它应该始终存在……谢谢!我已经更新了我的问题-我实际上需要在创建m_类之前运行一个方法。可能吗?也许我可以在“classInit”中这样做,但那不是很优雅。当我看到逗号运算符的用法时,我知道回答这个问题的人很聪明。当我看到函数try块的使用时,我知道回答这个问题的人是litb。当我看到回答这个问题的人是利特。。。我想我已经知道是他干的:)如果变量的构造函数包含多个参数,情况也会变得更复杂;然后,对于每个参数+1,您将需要这些函数中的一个,以便简明地推荐聪明的东西,而不是像其他低级答案一样,基于动态/指针的初始化。具有RVO和三元操作符的C++意味着我们不必在这个例子中到处乱放<代码>新的<代码>指针。我以为我们的咒语是不使用动态分配,除非我们有充分的理由?这不是一个。另一种方法是将Myclass初始化为某种虚拟僵尸状态,然后在知道该值后重新初始化。但我更喜欢指针。
class MemberClass
{
public:    
   MemberClass(int abc = 0){ }
};
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);
    }
};