如何抑制隐式复制构造函数/赋值运算符中的成员?

mil*_*sma 2 c++ oop

我知道隐式复制构造函数/赋值运算符对源对象进行成员明智的复制。

假设我的班级有 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;语句。找到它们并在它们后面添加一行太难了。

因此,我想要最少的代码更改来自定义对象的成员明智副本。我怎样才能做到这一点?

Sto*_*ica 5

我也同意@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)

  • @milesma - `return *this;` 是与函数返回类型的引用绑定。与修改成员无关。这就是交换的目的。否则你的任务不会做任何事情,更不用说重置`_mem`了。 (2认同)