我有一个相当庞大而冗长的类,其中隐式生成的复制构造函数 几乎 完全正确,除了一个特定的字段。
有没有办法编写一个调用隐式版本的用户定义的复制构造函数,然后在末尾添加一行或两行?或者我是否必须编写一个冗长的,(并且无聊且易于打字)用户定义的复制构造函数,该复制构造函数主要与隐式复制构造函数重复?
class MySimpleObject
{
private:
FieldA m_fieldA;
FieldB m_fieldB;
[... repeated a lot...]
SpecialField m_trickyField;
public:
MySimpleObject(const MySimpleObject& other)
{
ImplicitCopyCtor(*this,other); // This is what I want to simplify, instead of copying all the fields by hand.
m_trickyField.DoCloneSeparately(other.m_trickyField);
}
};
注意: SpecialField由第三方库提供,因此我无法对其进行重构或修改。我不知道为什么它没有正确复制,但它没有,我认为这是一个很好的理由。我喜欢将它包装在一个行为正常的类中。我会调查一下。
答案 0 :(得分:17)
fundamental theorem of software engineering是你的朋友:
struct MakeSpecialSnowflakeLessSpecial
{
MakeSpecialSnowflakeLessSpecial(const MakeSpecialSnowflakeLessSpecial& other)
{
m_trickyField.DoCloneSeparately(other.m_trickyField);
}
SpecialField m_trickyField;
};
class MySimpleObject
{
private:
FieldA m_fieldA;
FieldB m_fieldB;
[... repeated a lot...]
MakeSpecialSnowflakeLessSpecial m_special;
public:
MySimpleObject(const MySimpleObject&) = default;
};
答案 1 :(得分:4)
不,没有。
你最好的办法是修复有问题的成员。
快速解决方案可能是将其包装在一个破坏其复制语义的类中。
答案 2 :(得分:2)
您可以想到两个解决方案,我可以想到:
struct MySimpleObjectDefaultData
{
FieldA m_fieldA;
FieldB m_fieldB;
// [... repeated a lot...]
}
class MySimpleObject : private MySimpleObjectDefaultData
{
private:
SpecialField m_trickyField;
public:
MySimpleObject(const MySimpleObject& other)
: MySimpleObjectDefaultData( other )
{
m_trickyField.DoCloneSeparately(other.m_trickyField);
}
};
由于访问权限和字段类型保持完全相同,因此对其余代码的侵入性较小。您无需触及现有代码的其余部分,即可使此解决方案正常运行。此外,此解决方案更通用,因为您可以手动将任何后处理步骤应用于编译器生成的复制构造函数。
struct SpecialFieldWrapper : SpecialField
{
using SpecialField::SpecialField;
SpecialFieldWrapper( const SpecialFieldWrapper & other )
{
DoCloneSeparately( other.m_trickyField );
}
};
class MySimpleObject
{
private:
FieldA m_fieldA;
FieldB m_fieldB;
[... repeated a lot...]
SpecialFieldWrapper m_trickyField;
public:
MySimpleObject(const MySimpleObject& other)
{
ImplicitCopyCtor(*this,other); // This is what I want to simplify, instead of copying all the fields by hand.
m_trickyField.DoCloneSeparately(other.m_trickyField);
}
};
此解决方案可能比第一个更容易阅读。但是,类型稍有变化,这可以进一步更改您的代码。