我正在使用base-from-member成语,我现在坚持使用复制/移动构造函数。假设以下代码:
#include <iostream>
#include <string>
#include <boost/lexical_cast.hpp>
using namespace std;
struct A // base class
{
A(string &s) : s(s), c(0) { };
A(const A &a) : s(a.s), c(a.c) { };
void print() { cout << s << endl; c++; }
int print_count() { return c; }
string &s;
int c;
};
struct B_base // this class will be initialized before A
{
B_base(int i)
{
s = boost::lexical_cast<string>(i);
}
B_base(const B_base &other) : s(other.s) { };
string s;
};
struct B : B_base, A // main class
{
B(int i) : B_base(i), A(B_base::s) { }
B(const B &other) : B_base(other), A(other) { } // <-- problem here
using A::print;
using A::print_count;
};
int main()
{
B b(10);
b.print(); // prints '10'
cout << b.print_count() << endl; // prints '1'
B b1(b);
b1.print(); // prints '10'
A &a = b;
a.s = "FAIL"; // we modify b, not b1 here!
b1.print(); // but b1 prints 'FAIL' here --- error (it should still print '10')
cout << b.print_count() << " " << b1.print_count() << endl; // prints '1 3'
return 0;
}
这里的问题是引用A.s
(指向B_base::s
)从一个实例复制到另一个实例,而应该修改它以指向另一个B_base::s
。事情可能会更糟,如果先前的实例超出范围以悬挂引用结束。
我的问题是:如何使用成员基础成语制作正确的课程副本? (我认为移动构造函数类似于复制一个,对吗?)
答案 0 :(得分:0)
在这种情况下,您正在练习的成员基础成语意味着:您希望从class B
派生的A
必须使用B
的成员进行初始化( :string s
)。
B b(10);
B b1(b); // B(const B &other) : B_base(other), A(other) { }
// now A::s in b1 is a ref to b.s
A &a = b;// and a.s is a ref to b.s too.
a.s = "FAIL"; // we modify b, and A::s in b1 to!
这个问题可以通过复制构造函数来解决:
B(const B &other) : B_base(other), A(B_base::s) { }
此外,如果A::s
和B_base::s
具有相同的名称,则会使事情变得更难理解。
编辑:作为一名班级设计师,你必须决定你的复制构造函数的确切含义
例如,在这种情况下,您可能希望跟踪(使用A::c
)每个新创建对象A
的打印数量。我提出的复制构造函数就是这样做的。
A::c
复制到新的A
,它将被正确初始化,当使用{{1}的不同副本打印相同的原始字符串时,不会交叉实现}。如果这不是问题,您可以修改构造函数:
A
...
A(string &s, int _c=0) : s(s), c(_c) { };