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
How do I get bb = aa to work?
What you're missing here is that even though A and B are related types, std::list<A> and std::list<B> are actually unrelated types (other than both saying list). As such you can't use copy assignment to assign between them.
However, assuming that you're ok assigning the types A and B to each other using their assignment operators, you can use list's assign method to copy the range of iterators:
aa.assign(bb.begin(), bb.end());
bb.assign(aa.begin(), aa.end());
You can do this with a copy and a back_inserter:
std::copy(aa.begin(), aa.end(), back_inserter<list<B>>(bb));
but under the condition that the target element (here B) can be constructed from the source element (here A). So here, you'd need a B constructor based on an A object.
Online demo
Note: If you don't have the constructor needed for the copy in the target class, but you have some other way to build a target object from the source, you can consider using std::transform()
By the way, attention: a=b works, but might result in slicing.
That you can assign a object of type A to an object of type B does not mean that holds for list<A> and list<B> as well.
Instead of you can use std::copy:
std::copy(bb.begin(), bb.end(), std::back_inserter(aa)); // instead of aa = bb
EDIT: in order to use that you either have to call aa.resize(bb.size()) first, or better use a back_inserter as noted by @Christophe.
You should be clear about what you're doing here: it's either slicing (A = B) or assigning a non-final class (B = A). In order to avoid that, you should work with pointers and use the clone pattern.
As far as the compiler is concerned std::list<A> and std::list<B> are disjoint types. This makes sense if you consider that std::list has internally allocated memory for A objects. Trying to assign B objects into that space could be disasterous.
Imagine, for example, that B has an extra property. Now, if you're trying to store a B into memory large enough for an A, it will likely not fit. Similar logic can be used to see why the other direction also fails: if you store an A into space for a B, the compiler expects that the extra property of the B it believes to be at that space is valid. If you assigned an A though, that space has who-knows-what in it.
If you want this assignment to be able to work, you're going to need to use some form of indirection. For example, you could use two std::list<A*> instances or two std::list<std::shared_ptr<A>> instances. This then works because a B* can be safely treated as an A*, at least assuming that the classes are properly written.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With