[英]Right way to conditionally initialize a C++ member variable?
我确信这是一个非常简单的问题。 以下代码显示了我正在尝试执行的操作:
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
是使用空构造函数(不存在)创建的。 这样做的正确方法是什么? 我的猜测是使用指针并使用new
实例化m_class
,但我希望有一种更简单的方法。
编辑:我之前应该说过,但我的实际问题有一个额外的复杂性:我需要在初始化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);
}
};
是否有可能通过花哨的初始化列表技巧实现这一目标?
使用条件运算符。 如果表达式较大,请使用函数
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之前调用函数,可以在该成员之前放置一个struct并利用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_class
之前调用do_something()
。 请注意,在构造函数初始化程序列表完成之前,不允许调用MyClass
非静态成员函数。 该函数必须是其基类的成员,并且必须已完成基类'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)) {
}
};
它使用逗号运算符。 请注意,您可以使用function-try块捕获do_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 */ }
};
如果do_something
函数抛出导致无法创建MyClass
对象的异常,则会再次调用do_something
函数。 希望这可以帮助 :)
使用初始化列表语法:
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))
MyClass(int xyz) : m_class(xyz==42 ? 12 : 32) {}
要回答你修改过的问题,这有点棘手。 最简单的方法是使m_class
成为指针。 如果您真的希望它作为数据成员,那么您必须具有创造性。 创建一个新类(最好是在MyClass内部定义)。 它是否是需要被调用的函数。 首先将其包含在数据成员的声明中(这将使其成为第一个实例)。
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.
}
};
要么:
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
访问成员变量,并在析构函数中delete m_pClass
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.