13

我敢肯定这是一个非常简单的问题。以下代码显示了我正在尝试做的事情:

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

是否可以通过花哨的初始化列表技巧来实现这一点?

4

6 回答 6

27

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

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

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_classMyClass请注意,在构造函数初始化程序列表完成之前,不允许调用非静态成员函数。该函数必须是其基类的成员,并且必须已经完成基类的ctor才能使其工作。

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

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请注意,您可以使用 function-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希望这可以帮助 :)

于 2009-06-18T18:57:10.377 回答
5

使用初始化列表语法:

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))
于 2009-06-18T18:55:40.410 回答
5
 MyClass(int xyz) : m_class(xyz==42 ? 12 : 32) {}

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

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.
    }
};
于 2009-06-18T18:56:26.493 回答
0

或者:

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

如果您仍然想保持相同的语法。不过,成员初始化更有效。

于 2009-06-18T18:59:44.227 回答
0

试试这个:

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

这给了它一个默认值,以及你的默认构造函数。

于 2009-06-18T19:03:13.753 回答
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, 。delete m_pClass

于 2009-06-18T19:23:16.213 回答