calling derived using base* with base* as parameter

Pages: 12
hi,

what I'm doing is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>

using namespace std;

class base;
class a_derived;
class b_derived;

class base 
{
public:
	void f( base* p ){ p->_f(this); }

	virtual void _f( base* p ) = 0;

	//the backend
	virtual void __f( a_derived* p ) = 0;
	virtual void __f( b_derived* p ) = 0;
};

class a_derived : public base 
{
public:
	void _f( base* p ){ p->__f( this ); }
	void __f( b_derived* p ){ cout << "a::f(b)" << endl; }
	void __f( a_derived* p ){ cout << "a::f(a)" << endl; }
};

class b_derived : public base 
{
public:
	void _f( base* p ){ p->__f( this ); }
	void __f( b_derived* p ){ cout << "b::f(b)" << endl; }
	void __f( a_derived* p ){ cout << "b::f(a)" << endl; }
};

int main( int argc, char** args )
{
	base* a = new a_derived();
	base* b = new b_derived();

	a->f(b); //a::f(b)
	b->f(a); //b::f(a)

	return 0;
}


is there any nicer (ie that requires writing less functions etc.) way that a base can call a derived function using a base as a parameter, and it calls the correct derived function?
ie. none of them know what type they are, yet they're executing the function I want.

best regards,
Yours3lf
Last edited on
I think you oversimplified your example here. What it looks like you're asking to do would be an ambiguous overload which isn't allowed. If this is for something like a copy function then you don't have to do all of this since all of the common data members would be in the base class.

EDIT: Now if 'a' and 'b' were pointers to their respective classes this would be possible. You could have the base class hold a data member that indicated what class type the pointer resolves to but at that point it seems like it would be better to redesign your code if it is still possible.
Last edited on
it's intersection (is a inside b? so order matters) test with aabb vs aabb, aabb vs sphere, sphere vs sphere, sphere vs aabb
Last edited on
I've had a similar problem with trying to do 2-way polymorphism. I have yet to find a good solution =(
yes, I could've stored the type, I have methods for that, but the point was not storing the type.
it's intersection

So if object 'a' is a sphere and object 'b' is a ray then you want to see if 'b' intersects 'a' right?

If I understood you then you would just have to make the array of coordinates (or what ever is defining the dimensions of the object) accessible from the base class. I'd give the base class a pointer that gets set to the array containing the objects coordinates when the object is constructed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class base 
{
public:
	void f( base* p ){ p->_f(this); }

	virtual void _f( base* p ) = 0;

	//the backend
	virtual void __f( a_derived* p ) = 0;
	virtual void __f( b_derived* p ) = 0;

	auto Coords*;
};

class a_derived : public base 
{
public:
	a_derived(){ Coords = &Points;}

        int Points[360];

	void _f( base* p ){ p->__f( this ); }
	void __f( b_derived* p ){ cout << "a::f(b)" << endl; }
	void __f( a_derived* p ){ cout << "a::f(a)" << endl; }
};


Or something like that (I haven't finished my coffee yet). The choice of data type and size of the "Points" array is completely arbitrary.
no, these are bounding volumes, it's not ray-anything intersection, it's rather the is a inside b type of stuff, therefore order matters (that is why I included base::_f() and the others).
it wouldn't be too great to store anything else in these except those that are required by the mathematical definition (we could have millions of these), so I gues this is not an option.
I'm just going to see my way out of this thread now. We've now gone from outputting text based on data_type to some mathematical concept that you have yet to adequately describe. You are completely changing the parameters of your request with every post you make and your sentence structure seems to be degrading at an astonishing rate.
huh? no.
well, sorry I'm not yet used to this keyboard (it's way harder to push the buttons).
anyways, I think Disch actually got the question right.
This is a design flaw. If you have to change the base class to accommodate for an arbitrary new deriving class, that is a serious issue that needs to be resolved.
@LB thank you for pointing that out, is there any way to solve it? or should I completely rethink the whole thing?
For those of you who don't understand the problem:

Virtual functions provide a way to identify the type of an object, and run a different function based on that type.

So if you have 2 child classes A and B that inherit from a common parent... they would each have their own version of a function.

The problem here is the same concept... only he needs to identify two objects. So if you have those same classes A and B... you'd need four functions... one for AA pair, one for AB, one for BA, and one for BB.

This is particularly nasty not only because it grows exponentially.... but also because any solution is going to require some area of code to be aware of other classes. So it's difficult to keep it encapsulated.



The best approach I could come up with is to have each class return some kind of ID. Merge the ID from both objects involved in the collision somehow (ie, shift one of them, then OR them)... and throw that merged ID in a big switch, which will call the appropriate collision function.

With this approach, adding a new class involves several steps:
1) Add the actual class
2) Add X new intersection functions... one for where this class intersects with itself... and one for each other class.
3) Update the big switch to include those new functions.


Like I said... it's not a good approach. But I can't think of any better way to do it.
For those of you who don't understand the problem:


"Double Dispatch"
@ Disch: You only need a separate function for each data type if you need to handle each data type differently. If each class is only concerned about the properties of the base class then there is no need to define a different function for each combination of classes. LB is right, this is a design issue.

EDIT: I got flustered because the OP was posting the problem piecemeal. Every post he made added another design consideration that was never mentioned before.
Last edited on
You can map pairs of std::type_index to std::functions rather easily, and the map can be generated by global static initialization without any one part of the code having to know about all the classes. Even loading DLLs would work fine this way. The obvious cost is performance, but that's for the profiler to decide.
1
2
3
4
5
6
7
8
9
10
11
using DoubleDispatch = std::map<std::pair<std::type_index, std::type_index>, std::function<void (Base &, Base &)>>;
DoubleDispatch &dispatcher()
{
    static DoubleDispatch dd;
    return dd;
}
template<typename T, typename U>
void addDispatch(DoubleDispatch::mapped_type f)
{
    dispatcher()[{typeid(T), typeid(U)}] = f;
}
Last edited on
Then tell me, computergeek, how can you detect intersection between two circles without knowing they're both circles?

Or circle/rectangle?
Or rectangle/rectangle?
Or circle/triangle
etc
etc

Each shape (child class) needs to be handled differently. And each interaction needs its own logic.

EDIT:

Your previous suggestion of "making an array of points available in the base class" is one approach... but that would be extremely slow and clunky... and would restrict you to a finite, discrete coordinate system, rather than being able to work with real numbers.

Compare the logic for whether or not 2 circles intersect:

1
2
3
4
5
6
7
8
bool circleIntersect( Circle a, Circle b )
{
    auto vec = a.center - b.center;
    auto distance2 = (vec.x * vec.x) + (vec.y * vec.y);
    auto radius = a.radius + b.radius;

    return distance2 <= (radius*radius);
}


To the logic of:
- Generating a finite list of discrete points in a massive array.
- Checking each and every one of those points to see if they exist inside of another circle.



EDIT2:

LB wrote:
You can map pairs of std::type_index to std::functions rather easily, and the map can be generated by global static initialization without any one part of the code having to know about all the classes.


Ultimately you're going to have to have a series of functions which cover every permutation of all shapes' intersections. So at least that part of the code will need to be aware of all classes.


Building this map automatically is also a challenge without a centralized area knowing all the classes. It doesn't seem to be as easy as you make it sound.

Whenever the N'th class is added... you have to add (at least) N permutations to the map. How can you do generate permutations without knowing what classes you're dealing with?

Ex: If I already have Square and Triangle functions set up.... when I add a 3rd class Circle... I have to add at least 3 more functions (OP said he will actually need 5):

Circle/Circle
Circle/Square (need to be aware of Square's existence)
Circle/Triangle (need to be aware of Triangle's existence)
Square/Circle (OP said order is important)
Triangle/Circle (ditto)


If you have a way to automate this that doesn't require maintaining a central list... that is exactly what the OP is asking for. I don't have a good solution. If you do, I've love to hear it, as I'm interested in this as well.
Last edited on
Lots of post editing, gah. Let's all reread.
How I would do it? Off the top of my head I would try to use trigonometry; each object would hold a function that describes what Cartiesian points they occupy on the the plane. Of course that won't work for the OP since it involves iterating through all of the coordinate points in each shape but no one knew that he was dealing with bounding volumes until two hours after his initial post.
@ Computergeek:

While it may have helped if the OP gave the full context up front... hopefully now we all understand what he's talking about.

So now... if you still don't understand the problem, please ask about what part is tripping you up so we can help clarify.

And if you do understand the problem, and if you have a solution, then I am very interested in hearing it. (no sarcasm intended... I've thought about this problem many times in the past and would seriously love a good solution to it)
@ LB:

Your approach still leaves lingering issues.

For one, you are passing base classes references to your intersection functions. Which means all of them will have to downcast. No big deal I suppose, but it is another thing to have to deal with.

(edit: note my approach involved downcasting as well... which is another reason why I didn't like it)

Also... how do you call addDispatch without a central list of classes?

Your approach seems similar to my suggestion -- the only difference being you use a map for lookup rather than a switch.
Last edited on
Pages: 12