Weapon
的类,其中包含两个构造函数。一个构造函数需要输入一些参数以生成自定义武器,另一个构造函数则会获得默认武器(CHAIN_GUN
)。Weapon::Weapon (void) {
// Standard weapon
*this = getWeapon(CHAIN_GUN);
return;
}
问题:使用 *this
和 operator=
来初始化一个类会有负面影响吗?Weapon
的类,其中包含两个构造函数。一个构造函数需要输入一些参数以生成自定义武器,另一个构造函数则会获得默认武器(CHAIN_GUN
)。Weapon::Weapon (void) {
// Standard weapon
*this = getWeapon(CHAIN_GUN);
return;
}
问题:使用 *this
和 operator=
来初始化一个类会有负面影响吗?为什么这是个糟糕的想法?
我从未见过使用赋值运算符实现默认构造函数,老实说,我不建议这样做,在代码审核期间也不支持。
这种代码的主要问题在于,根据定义,我们正在构造两个对象(而不是一个),并调用成员函数,这意味着我们需要构造所有成员两次,并稍后通过调用赋值运算符来复制/移动初始化所有成员。
请求构造1个对象时,我们构造2个对象,然后将值从第二个对象复制到第一个对象并丢弃第二个对象,这是不直观的。
结论:不要这样做。
(注意:如果Weapon
有基类,则情况会更糟)
建议解决方案
在您的特定情况下,最好在构造函数中使用默认参数,如下例所示。
class Weapon {
public:
Weapon(WeaponType w_type = CHAIN_GUN);
...
}
Weapon w1; // w_type = CHAIN_GUN
Weapon w2 (KNOWLEDGE); // the most powerful weapon
(注意:以上的另一种方法是使用C++11中可用的委托构造函数)
explicit
可以避免隐式类型转换,这是一个好的习惯。 - Dave使用赋值运算符来实现构造函数很少是一个好主意。在你的情况下,例如,你可以只使用默认参数:
Weapon::Weapon(GunType g = CHAIN_GUN)
: // Initialize members based on g
{
}
在其他情况下,您可以使用委托构造函数(在C++11或更高版本中):Weapon::Weapon(GunType g)
: // Initialize members based on g
{
}
Weapon::Weapon()
: Weapon(CHAIN_GUN) // Delegate to other constructor
{
}
construct_me(GunType g)
的公共函数,在每个构造函数中调用它。 - M.M需要记住的一件事情是,如果operator=
- 或任何它调用的函数 - 是virtual
,那么派生类的版本不会被调用。这可能会导致未初始化的字段和后续的未定义行为,但这完全取决于你的数据成员。
更一般而言,如果基类和数据成员具有构造函数或出现在初始值列表中(或在C++11中出现在类声明中进行赋值),则保证它们已被初始化 - 因此除了上述的virtual
问题外,operator=
通常可以在没有未定义行为的情况下工作。
如果在调用operator=()
之前已对基类或成员进行了初始化,则无论如何都会覆盖初始值,优化器可能能够删除第一个初始化。例如:
std::string s_;
Q* p_;
int i_;
X(const X& rhs)
: p_(nullptr) // have to initialise as operator= will delete
{
// s_ is default initialised then assigned - optimiser may help
// i_ not initialised but if operator= sets without reading, all's good
*this = rhs;
}
operator =
的人也可能没有检查构造函数是否被滥用....getWeapon()
使用原型或享元模式并尝试复制构造它返回的Weapon
,则可能导致无限递归,从而导致堆栈溢出。
getWeapon(CHAIN_GUN);
的问题。如果我们需要一个基于武器类型创建武器的函数,那么Weapon(Weapon_Type);
构造函数似乎是一个合理的选择。话虽如此,有时候会出现罕见但大量的边缘情况,其中getWeapon
可能会返回除Weapon
对象之外的其他东西,但仍然可以分配给Weapon
,或者由于构建/部署原因而保持分离....=
赋值运算符,以便让 Weapon
在构造后更改其类型,则使用赋值实现构造函数就可以很好地解决问题,并且是集中初始化代码的一种好方法。 但是,如果一个 Weapon
在构造后不打算更改其类型,则没有必要创建非拷贝的 =
赋值运算符,更不用说用于初始化了。我肯定是的。
您已经在“getWeapon”函数内创建了对象,然后将其复制,这可能是一项长时间操作。因此,至少您必须尝试移动语义。
但是。 如果在“getWeapon”内部调用构造函数(而且您确实这样做了,某种方式下,“getWeapon”必须创建要返回的类),则会创建非常不清晰的架构,其中一个构造函数调用调用另一个构造函数的函数。
我认为您必须将参数初始化分离到私有函数中,并从您想要的构造函数中调用它们。