提问人:Y. L. 提问时间:4/17/2016 最后编辑:PrixY. L. 更新时间:4/18/2016 访问量:445
C++、std::列表、赋值、继承
C++, std::list, assignment, inheritance
问:
class A, B;
class A {
public:
A& operator= ( const A &rhs ) { return *this; }
};
class B: public A {
public:
B& operator= ( const A &rhs ) { return *this; }
};
A a;
B b;
std::list < A > aa;
std::list < B > bb;
a = b; // works
b = a; // works
// aa = bb; // fails
// bb = aa; // fails
如何让 bb = aa 工作?
答:
您可以将类型的对象分配给类型的对象并不意味着 for 和 也成立。A
B
list<A>
list<B>
代替你可以使用:std::copy
std::copy(bb.begin(), bb.end(), std::back_inserter(aa)); // instead of aa = bb
编辑:为了使用它,您必须先调用,或者最好使用@Christophe指出的 a。aa.resize(bb.size())
back_inserter
你应该清楚你在这里做什么:它要么是切片(),要么是分配一个非最终类()。为了避免这种情况,您应该使用指针并使用克隆模式。A = B
B = A
您可以使用副本
和back_inserter
来执行此操作:
std::copy(aa.begin(), aa.end(), back_inserter<list<B>>(bb));
但条件是目标元素(此处为 B)可以从源元素(此处为 A)构造。所以在这里,你需要一个基于 A 对象的 B 构造函数。
注意:如果你没有目标类中复制所需的构造函数,但你有其他方法可以从源代码构建目标对象,你可以考虑使用 std::transform()
顺便说一句,注意:有效,但可能会导致切片。a=b
评论
std::list::assign(iter, iter)
就编译器而言,并且是不相交的类型。如果您认为它已为对象分配了内部内存,则这是有道理的。尝试将对象分配到该空间中可能是灾难性的。std::list<A>
std::list<B>
std::list
A
B
例如,假设 B 有一个额外的属性。现在,如果您尝试将 存储到足够大的内存中,那么它可能不适合。类似的逻辑可以用来查看为什么另一个方向也失败了:如果你将一个 存储到 空间 ,编译器期望它认为在该空间的额外属性是有效的。如果你分配了一个,那么这个空间里有谁知道什么。B
A
A
B
B
A
如果您希望此任务能够工作,则需要使用某种形式的间接操作。例如,您可以使用两个实例或两个实例。这样就可以了,因为 可以安全地将 视为 ,至少假设类编写正确。std::list<A*>
std::list<std::shared_ptr<A>>
B*
A*
评论
b=a
std::list<B>
std::list<B>
std::list<A>
A
std::list<B>
bb = aa
std::list<B>
std::list<A>
你在这里缺少的是,即使 和 是相关的类型,并且实际上是不相关的类型(除了两者都说)。因此,您不能使用副本分配在它们之间进行分配。A
B
std::list<A>
std::list<B>
list
但是,假设您可以使用它们的赋值运算符将类型和类型相互赋值,则可以使用 的方法复制迭代器的范围:A
B
list
assign
aa.assign(bb.begin(), bb.end());
bb.assign(aa.begin(), aa.end());
我不认为有人真的试图回答如何完成分配的问题bb = aa;
如前所述,不能将隐式强制转换运算符或赋值运算符定义为自由运算符。但你确实有两个选择。他们俩都依赖于这个集合的子类化......只要您不允许任何其他状态,就可以了。std::list<B>
选项 #1 是定义为 的子类,并将使用这些类。( 将获得一个额外的赋值运算符。BB
std::list<B>
bb
BB
选项 #2 是使用帮助程序类,并且可能更接近您的原始意图。帮助程序类的定义与上面描述的类类似,将隐式转换运算符添加回 。BB
std::list<B>
下面是一个完整的示例:
class A {};
class B: public A {
public:
B() = default;
B( const A &rhs ) {} // Empty because A and B are not defined with any state.
B& operator= ( const A &rhs ) { return *this; }
};
class BB : public std::list<B> {
public:
BB() = default;
BB(const std::list<A> &aa) { assign( aa.begin(), aa.end() ); }
BB& operator= ( const std::list<A> &rhs ) { assign(rhs.begin(), rhs.end()); return *this; }
operator std::list<B>() { return *this; }
};
// No new member variables or virtual methods are allowed.
static_assert( sizeof (std::list<B>) == sizeof (BB), "Bad derivation of std::list<B>" );
A a;
B b;
b = a; // works
std::list<A> aa;
std::list<B> bb;
BB helper;
bb = helper = aa; // Option #2; bb is std::list<B>
或者您可以直接使用:BB
BB bb = aa; // Option #1; use bb just like std::list<B>
评论