我知道隐式复制构造函数/赋值运算符对源对象进行成员明智的复制。
假设我的班级有 1000 名成员。我想在进行赋值赋值时抑制其中一个成员(并且应用默认值),其他 999 个成员仍然使用成员明智的复制作为隐式赋值运算符。
例如:
class Foo
{
std::string s1;
std::string s2;
std::string s3;
....
std::string s1000;
};
Run Code Online (Sandbox Code Playgroud)
然后我们用一些值填充对象 f1:
Foo f1;
f1.s1 = "a";
f1.s2 = "b";
f1.s3 = "c";
...
Run Code Online (Sandbox Code Playgroud)
现在我们复制将 f1(源)分配给 f2(目标)
Foo f2 = f1;
Run Code Online (Sandbox Code Playgroud)
如果我想抑制“s2”,如何才能达到以下结果?
assert(f2.s1 == "a");
assert(f2.s2 == ""); //default value
assert(f2.s3 == "c");
Run Code Online (Sandbox Code Playgroud)
我知道提供复制构造函数/赋值运算符将解决这个问题。
class Foo
{
Foo( const Foo& other)
{
s1 = other.s1;
//s2 = other.s2; //suppress s2
s3 = other.s3;
...
s1000 = other.s1000;
};
Foo& Foo::operator=( const Foo& other)
{
s1 = other.s1;
//s2 = other.s2; //suppress s2
s3 = other.s3;
...
s1000 = other.s1000;
return *this;
};
std::string s1;
std::string s2;
std::string s3;
....
std::string s1000;
};
Run Code Online (Sandbox Code Playgroud)
然而,我有1000名会员。我不想实现这么大的功能。
如果我实现这样的功能:
class Foo
{
Foo( const Foo& other)
{
*this = other;
s2 = "";
};
Foo& Foo::operator=( const Foo& other)
{
*this = other;
s2 = "";
return *this;
};
}
Run Code Online (Sandbox Code Playgroud)
显然,这是无限递归的。
目前我唯一的选择是:
Foo f2 = f1;
f2.s2 = "";
Run Code Online (Sandbox Code Playgroud)
然而,假设有数千个Foo f2 = f1;语句。找到它们并在它们后面添加一行太难了。
因此,我想要最少的代码更改来自定义对象的成员明智副本。我怎样才能做到这一点?
我也同意@gsamaras 的观点,即你必须记住单一责任原则。但与他们的答案不同的是,我认为你可以鱼与熊掌兼得。
让我们检查一下您班级的职责。其一,它不关心所有数据成员是如何复制的。该责任被委托给每个成员所属的类型。我们应该坚持这一点,因为这种认识清楚地表明了谁应该负责。
有问题的数据成员s2是一个std::string. 该类型会自我复制。但如果我们把它包裹起来呢?
template<typename T>
class suppress_copies {
T _mem;
public:
// Allow changing the held member
operator T&() { return _mem; }
T& get() { return _mem; }
suppress_copies() = default;
// But stop automatic copies (potentially even handles moves)
suppress_copies(suppress_copies const&) {} // default initialize the member
suppress_copies& operator=(suppress_copies o) { // Accept default initialized "other"
using std::swap;
swap(_mem, o._mem);
return *this;
}
};
Run Code Online (Sandbox Code Playgroud)
差不多就是这样,这是负责抑制副本的类型。只需使用此包装器指定成员即可:
suppress_copies<std::string> s2;
Run Code Online (Sandbox Code Playgroud)