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