请查看以下代码并告诉我将来是否会导致问题,如果是,请如何避免这些问题。
class Note
{
int id;
std::string text;
public:
// ... some ctors here...
Note(const Note& other) : id(other.id), text(other.text) {}
void operator=(const Note& other) // returns void: no chaining wanted
{
if (&other == this) return;
text = other.text;
// NB: id stays the same!
}
...
};
简而言之,我希望复制构造函数能够创建对象的精确副本,包括其(数据库)ID字段。另一方面,当我分配时,我只想复制数据字段。 但我有一些担忧,因为通常复制ctor和operator =具有相同的语义。
id字段仅供Note及其朋友使用。对于所有其他客户端,赋值运算符确实创建了精确副本。用例:当我想编辑一个笔记时,我使用copy ctor创建一个副本,编辑它,然后在管理Notes的Notebook类上调用save:
Note n(notebook.getNote(id));
n = editNote(n); // pass by const ref (for the case edit is canceled)
notebook.saveNote(n);
另一方面,当我想创建一个与现有音符具有相同内容的全新音符时,我可以这样做:
Note n;
n = notebook.getNote(id);
n.setText("This is a copy");
notebook.addNote(n);
这种做法是否合理?如果没有,请指出可能的负面后果是什么!非常感谢!
答案 0 :(得分:9)
如果您希望语义与赋值运算符的预期值不匹配,则不要使用它。相反,通过声明私有operator=
来禁用它,并定义一个名称能够明确发生了什么的函数,例如copyDataFields
。
答案 1 :(得分:4)
虽然这可能适用于您的具体情况,但我不会推荐它。
STL之类的库期望复制构造函数和赋值运算符“像它们应该的那样”工作。如果您违反了C ++语义,那么您可能会发现对象的STL容器无法正常工作。在不同情况下,STL将根据容器调用复制构造函数和赋值运算符。
当您的代码没有按照您的想法执行操作时,很容易感到困惑。
答案 2 :(得分:1)
从技术上讲,它是可行的,技术上可行,但我不这样做。 我看到的问题是:
您可以更改C ++填充程序所知的赋值运算符的“自然”语义。
由于语义不同,两个双操作,复制构造和赋值不一致。
该解决方案容易出错,因为很容易意外调用复制构造函数,即使它看起来像是赋值。如果程序员以这种方式编写您的第二个用例:
Note n = notebook.getNote(id);
然后调用复制构造函数, not assignment ,因此您将n
作为与预期不同的对象。
为什么不明确表达你的意图:
Note& Notebook::editNote(int id);
Note Notebook::createNote(int id);