I'm working off of someone's code. There is a vector of struct P
(Segment
). I want to have different types of P
. Therefore I defined struct P2 : P
. But, since Segment
takes just P
and not P*
, I cannot add element of type P2
to the Segment
and use dynamic_cast
since it will create a new element of type P and copy just i
and I lose the name
information.
What are my options here? Do I just have to change vector<P>
to vector<P*>
and adjust the code everywhere it's being used or create my own type Segment vector<P*>
and use where I need it?
Also, why it was used vector<P>
and not vector<P*>
from the beginning since the vector can have hundreds and even thousands of elements?
struct P
{
int i;
P(int i2) : i(i2) {}
}
struct P2 : P
{
string name;
P2(string name2, int i) : P(i), name(name2) {}
}
struct P3 : P
{
...
}
using Segment = vector<P>;
You can basically use one of the following concepts:
Inheritance/Polymorphism: As you suggested, but then please with a std::vector<std::unique_ptr<P>>
. Using a raw pointer as in vector<P*>
is discouraged in modern C++, as the vector usually owns the objects. Moreover, I would then define a reasonable interface -- other than in your current example with P2
.
Type-safe unions: For example, a std::variant<P,P2>
, which can contain one of the two types. You then further need to define visitors which act specifically on the contained type.
Type erasure: define a common interface as a new class and map the classes to it. In the simplest version, it's just a std::function<std::string()>
which captures, e.g., the parenthesis-operator of the classes. This can be thought of as inheritance without base classes.
There's probably more approaches, but those are imo the most common ones.