c++ 仅部分赋值时赋值运算符出现问题

bkhjykvo  于 2023-02-01  发布在  其他
关注(0)|答案(1)|浏览(179)

考虑这段代码。我已经为Person定义了一个复制构造函数,它将复制除了一个数据之外的所有数据,即它的DontCopy数据成员。但是我似乎不能用赋值运算符完成同样的事情。除了下面我已经做过的之外,还有什么最好的方法来完成它呢?目前,我只手动设置了name成员。如果Person有数百个成员需要复制,只有一个成员不需要复制,该怎么办?复制构造函数会处理这个问题,而赋值运算符不会。

#include <iostream>
#define show(variable) std::cout << #variable << " = " << variable << '\n';

struct DontCopy {
    class Person& subject;
    DontCopy (Person& p) : subject(p) { }
};

class PersonDataDoCopy {
protected:
    std::string name;
    PersonDataDoCopy (const std::string& n) : name(n) { }
    PersonDataDoCopy() = default;
};

class Person : private PersonDataDoCopy {
    DontCopy dontCopy{*this};
public:
    Person (const std::string& n) : PersonDataDoCopy(n) { }
    Person (const Person& other) : PersonDataDoCopy(other) { }  // 'dontCopy' is not copied from 'other'.
    Person (Person&& other) : PersonDataDoCopy(std::move(other)) { }  // 'dontCopy' is not copied from 'other'.
    Person& operator= (const Person& other) {
        if (this == &other)
            return *this;
//      static_cast<PersonDataDoCopy>(*this) = PersonDataDoCopy(other);  // Does not copy data from PersonDataDoCopy
//      *this = static_cast<Person&>(PersonDataDoCopy(other));  // Does not compile.
        name = other.name;  // Need more general solution than this.
        return *this;
    }
    Person() = default;
    void display() const { show(name)  show(this)  show(&dontCopy.subject); }
};

int main() {
    Person bob("Bob");
    bob.display();
    std::cout << '\n';
    Person clone1(bob);
    clone1.display();
    std::cout << '\n';
    Person clone2("");
    clone2 = bob;
    clone2.display();
}

输出:

name = Bob
this = 0x6ffde0
&dontCopy.subject = 0x6ffde0

name = Bob
this = 0x6ffdd0
&dontCopy.subject = 0x6ffdd0

name = Bob
this = 0x6ffdc0
&dontCopy.subject = 0x6ffdc0
uemypmqf

uemypmqf1#

如果不想逐个复制每个数据成员,可以将所有要复制的数据放入另一个结构中,类似于不复制结构。将所有要复制的数据成员放入该结构中,然后只需将该结构复制到新对象上。
然而,对于类来说,这不是一个特别好的设计,我建议如果你有一个既有数百个数据成员又需要复制构造函数的类,你最好重新设计这个类,把它分解一下。
还有一个问题是在复制构造函数中有一个非复制的数据成员。当你复制一个对象时,大多数人会期望你收到一个对象的精确副本,而不是一个缺少一些东西的部分副本。如果有人试图将对象的副本传递给一个函数,而没有注意到复制构造函数在做什么,这可能会导致bug。
如果你的类包含了不应该被复制的数据,最好将复制构造函数标记为已删除,并使类不可复制。如果你真的需要部分复制行为,你可以将其添加为一个方法,其名称更明显地表明它正在做什么。

相关问题