Hacker News new | ask | show | jobs
Why can't I pass std:vector<Child*> as std:vector<Parent*>? (mcla.ug)
2 points by lochsh 2160 days ago
1 comments

It's not just C++, nor is it just because of assumptions of the underlying implementation. This is a direct result of type-safety. It would never be "safe" to do the following, regardless of the language:

    std::vector<Parent*> children_as_parents = *reinterpret_cast<std::vector<Parent*>*>(&children);    
So let's say I have a X = list<Puppy> and Puppy IS-An Animal.

Then I call append_random_animal(list<Animal> arg) with argument X. If it were true that list<Puppy> IS-A list<Animal> that should be safe, right? (it isn't). But then that function, operating on list<Animal>, could quite legally append something else, like an Alligator which IS-An Animal to the list which is a list<Animal>. But that argument was actually X, a list of Puppies you'd end up with a list of mostly puppies and some alligators which shouldn't be possible. That could get very messy if we later pass that list X to pet(list<Puppy>) when it contains an element of type Alligator...

This is a form of the covariance and contravariance concept.

https://en.wikipedia.org/wiki/Covariance_and_contravariance_...

This is not specific to C++. It's a fundamental rule of polymorphism.

Arrays, Lists, and containers can be covariant (the authors expectation) only when they are read-only. They can be contravariant when they are write-only, which would be pretty unusual. So a mutable list must be invariant.

The fact that C++ does not provide type-safe immutable, read-only containers that are covariant is probably due to the difficulty of representing such.

Thanks for bringing up variance -- this is a concept I've since learned about and have added a small update to the blog post about.

I understand your point about the `children_as_parents` example, I've added another update to point out that the mutability of the vector makes it problematic to have the `children` variable.