c++: exact type of contained objects without casts

By : Simon
Source: Stackoverflow.com
Question!

I got the classic Shape hierarchy example...

struct Shape { // abstract type
    Shape (int x, int y);

    int x;
    int y;
};

struct Rectangle : public Shape {
    Rectangle (int x, int y, int w, int h);

    int w;
    int h;
};

struct Circle : public Shape {
    Circle (int x, int y, int r);

    int r;
};

a Shapes container, filled with Rectangles and Circles

std::list<Shape*> container;

and printing functions (in my case, those are collision detection functions)

void print_types (Shape&, Shape&) {
    std::cout << "Shape, Shape" << std::endl;
}

void print_types (Rectangle&, Rectangle&) {
    std::cout << "Rectangle, Rectangle" << std::endl;
}

void print_types (Rectangle&, Circle&) {
    ...

Course, when I'm doing this:

std::list<Shape*> it;
Rectangle r (0, 0, 32, 32);

for (it = container.begin(); it != container.end(); it++)
     print_types(r, **it);

I don't want to print only "Shape, Shape" lines. I know virtual methods, dynamic_casts and visitors. But is there any elegant way to get out of it without those solutions and keep my external functions ?

By : Simon


Answers

I can't call it elegant, and it has several pitfalls, but the classic way to do this before dynamic_cast was to have a virtual function, say virtual char* name(), in Shape and have each derived class override that function to return the correct name.

The most obvious pitfall is that you must maintain the whole thing by hand.



Responding to the edit of the problem:

The best solution is still to find a virtual method that will deliver what is required. For detecting shape collisions, perhaps you could have a function that converts each shape to a polygon (set of lines) and do the detection on that.

C uses the type you declared at compile-time to select which overloaded function to call; it doesn't have the ability to make that selection at run-time. That's why you're seeing "Shape,Shape" as output each time. There's a way to help the compiler out but it's going to be tedious. Try to convert each Shape* to the appropriate type, and if it succeeds you can call a more specific function.

I'm not really advocating this; you can see how it gets out of hand with just two shapes, imagine how ugly it gets as you add more! Still it shows how to do what you were trying to do in C .

void print_types (Rectangle*, Rectangle*) {
    std::cout 


The short answer is no, function calls are resolved at compile-time. So there is no way (AFAIK) to do this with your existing free functions.

I believe you will have to invest in a double-dispatch mechanism, or do what @Peter suggests in his answer (which sounds more elegant).



This video can help you solving your question :)
By: admin