7

I want to use inheritance to have an object treated in a different way depending on where in the hierarchy it falls

(similar to this C# question)

Assume you build a hierarchy of Shape objects like:

class Shape {} ;
class Sphere : public Shape {} ;
class Triangle : public Shape {} ; ...

You then equip a Ray class with methods like:

class Ray
{
    Intersection intersects( const Sphere * s ) ;
    Intersection intersects( const Triangle * t ) ;
};

You store an array of assorted Shape* of various types and call

vector<Shape*> shapes ; ...
//foreach shape..
Intersection int = ray.intersects( shapes[ i ] )

But you get the compiler error

error C2664: 'Intersection Ray::intersects(const Sphere *) const' : cannot convert parameter 1 from 'Shape *const ' to 'const Sphere *'

What did you do wrong?

Is the only way to do it the other way around, with

class Shape
{
    virtual Intersection intersects( const Ray* ray )=0 ;
} ;

then each class override intersects? Then calls to

//foreach shape..
Intersection int = shapes[i]->intersects( ray ) ;

Can you do it the first way I showed or NEVER?

Community
  • 1
  • 1
bobobobo
  • 64,917
  • 62
  • 258
  • 363

3 Answers3

4

You have to do it the other way around. Overload resolution takes place at compile-time, when the type of what you're calling it with is a Shape*.

Puppy
  • 144,682
  • 38
  • 256
  • 465
4

No, you can't do it the first way. Overload resolution in C++ is based on the static types of function arguments. It is resolved at compile time. In your example the static type is Shape * and there's no function in your class that would accept a Shape * (hence the error). The compiler doesn't care that your pointer might actually point to a Sphere at run time.

To implement what you are trying to implement you have to "channel" your calls through a facility that relies on dynamic types of the objects, i.e. through virtual function calls, which is what you do in your second example.

Your second example is a bit simplified, since the type of one of the objects involved is known at compile time (Ray). In a more complicated case both objects involved in an "intersection" could be dynamically type. If you care to handle something like that you can use so called "double dispatch" technique (search for it).

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
0

May be you can pull this with RTTI information. I haven't done it but it might be possible.

class Ray
{
    Intersection intersects( const Sphere * s ) ;
    Intersection intersects( const Triangle * t ) ;
    Intersection intersects( const Shape * s ) {
       //act on RTTI info, or 
       //use dynamic_cast to other types and check if the result is NULL or not
    }
};
Cem Kalyoncu
  • 14,120
  • 4
  • 40
  • 62