The specific case of drawing is a bad example because it follows a highly inefficient data path. Drawing is best done in large batches with a small number of calls because each call has an overhead. Calling each object results in tiny batches of size 1 and an enormous number of draw calls, which is the worst case for drawing hardware.
There are generally two patterns used.
In one situation you would use a shared interface and process them as a group. Instead of making Shape have Draw, you might have an interface called "Drawable"
For a C++ loop, you might have something like this:
...
for( size_t i = 0; i < SceneList.Size(); i++ ) // I'd prefer a newer ranged for loop, but whatever works.
{
if( Drawable* drawable = dynamic_cast<Drawable*>SceneList.GetItem[i] )
{
drawable->Draw();
}
}
There is a small cost to be paid for the dynamic cast, but since it will return a null pointer if the cast fails and it gracefully handles a bunch of data hierarchy problems, the cost is generally something you would pay anyway if you're detecting that an operation is supported.
Alternatively, if you don't want to pay for a conversion or a type test you can provide a function that is called for every object rather than just the specific interface functions, and implement the function differently based on the derived type of object:
For that style of system:
//Do this:
for( size_t actorIdx = 0; actorIdx < actors.count; ++actorIdx )
{
actors[actorIdx]->DoPrimaryAction();
}
//Not this:
for( size_t actorIdx = 0; actorIdx < actors.count; ++actorIdx )
{
if(actors[actorIdx]->type == ActorType.Wizard)
actors[actorIdx]->DoFireball();
else if(actors[actorIdx]->type == ActorType.Warrior)
actors[actorIdx]->DoSwordSwing();
else if(actors[actorIdx]->type == ActorType.Rogue)
actors[actorIdx]->DoKnifeStab();
else if(actors[actorIdx]->type == ActorType.Archer)
actors[actorIdx]->DoFireBow();
...
}
In both cases your code would not know or care about the concrete class it has. There are a collection of things that all implement the same interface. You have a factor method somewhere that created the things for you. The things might be triangles or squares or circles, but you don't care because you only care about shapes. Or the things might be wizards and warriors and rogues, but you don't care because you only care about actor objects. When you follow SOLID principles, you should generally be focused on abstractions, not the actual objects.