This is a follow-up to my question here: Updating data members of different derived classes of the same base class within a vector
I am building a 3D gridded model in C++ which has different cell types, all stored within a vector that is in a Grid class. I have defined a base GridCell class and I also have several derived classes GridCell1, GridCell2, GridCell3, and so on.
Into the model processes I pass a GridCell object. The GridCell object type (which derived class) that is passed will work with the receiving model processes. In other words, the model processes The model processes were designed (possibly incorrectly) with different functions expecting to act the on appropriate derived objects' data members. Which, of course, they can't see because the the object is pulled from the std::vector<gridCell*> gridCellVector so it only sees the object as a pointer to the base class. At this point, I have two options: 1) Rewrite my model processes, 2) use static_cast or dynamic_cast to downcast the passed object.
Question: In this scenario, when my model processes (which are only run on the right type of GridCell object) know what derived class they are receiving, should I use static_cast or dynamic_cast? People seem to really frown on the use of these tools. Why should I stay away from using these?
Sometimes casting is inevitable because polymorphism does not solve every problem. However polymorphism was actually designed to remove the need to know the type. If you need to know the type then you have to ask if polymorphism is the right tool for the job, or else if you have failed to implement polymorphism correctly.
The ideal is that each object knows its own behaviour so that no one else needs to make if/else decisions when dealing with the general type.
To that effect you would normally put the processing code inside the type itself rather than have external processing routines that need to make if/else decisions for each object they receive.
So whereas casting is not inherently bad because sometimes it is necessary, it is also potentially a symptom of poor design if you need to use it.
Question: In this scenario, when my model processes (which are only run on the right type of GridCell object) know what derived class they are receiving, should I use static_cast or dynamic_cast? People seem to really frown on the use of these tools. Why should I stay away from using these?
If you really know the type then use static_cast (its faster) otherwise use dynamic_cast.
An alternative to casting:
One "trick" you can use, which effectively is casting, is to use polymorphism to select the correct type for you.
What you can do is add a virtual function to your base class GridCell that takes the object of the class that is processing the subtypes separately and get the overriding subtypes to call the relevant processing function themselves. This way the type inherently knows how it needs to be processed.
An example
class Processor
{
public:
void process_1(class GridCell1* cell)
{
std::cout << "processing type 1\n";
}
void process_2(class GridCell2* cell)
{
std::cout << "processing type 2\n";
}
};
class GridCell
{
public:
virtual ~GridCell() {}
virtual void process(Processor& proc) = 0;
};
class GridCell1
: public GridCell
{
public:
void process(Processor& proc) override
{
proc.process_1(this);
}
};
class GridCell2
: public GridCell
{
public:
void process(Processor& proc) override
{
proc.process_2(this);
}
};
class Grid
{
std::vector<GridCell*> gridCellVector;
public:
Grid()
{
gridCellVector.push_back(new GridCell1);
gridCellVector.push_back(new GridCell1);
gridCellVector.push_back(new GridCell2);
gridCellVector.push_back(new GridCell1);
gridCellVector.push_back(new GridCell2);
gridCellVector.push_back(new GridCell1);
}
~Grid() { for(auto cell: gridCellVector) delete cell; }
void process()
{
Processor proc;
for(auto cell: gridCellVector)
cell->process(proc);
}
};
int main ()
{
Grid grid;
grid.process();
}
Output:
processing type 1
processing type 1
processing type 2
processing type 1
processing type 2
processing type 1
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