Double dispatch (makes no sense!)

S

saneman

I am trying to use double dispatch in the below code:

#include <iostream>

class Box;
class Sphere;


class geometry_type
{
public:
virtual void haps(geometry_type* other)=0;
virtual void collideWith(Box* other)=0;
virtual void collideWith(Sphere* other) = 0;
};

class Box : public geometry_type
{
public :
Box() {}

virtual void haps(geometry_type* other)
{
other->collideWith(this);
}

virtual void collideWith(Sphere* other) {
std::cout << "Sphere collision with Sphere" << std::endl;
}

virtual void collideWith(Box* other) {
std::cout << "Box collision with Box" << std::endl;
}


};

class Sphere : public geometry_type
{
public :
Sphere() {}

virtual void haps(geometry_type* other)
{
other->collideWith(this);
}

virtual void collideWith(Sphere* other) {
std::cout << "Sphere collision with Sphere" << std::endl;
}

virtual void collideWith(Box* other) {
std::cout << "Sphere collision with Box" << std::endl;
}


};


void narrow_phase(geometry_type* G1, geometry_type* G2)
{
G1->haps(G2);
}

int main()
{
Box* BoxA = new Box();
Sphere* SphereA = new Sphere();

BoxA->collideWith(BoxA);
SphereA->collideWith(BoxA);

// Should print box collide with box.
narrow_phase(BoxA, BoxA);

// Should print sphere collide with box.
narrow_phase(SphereA, BoxA);

// Should print box collide with sphere.
narrow_phase(BoxA, SphereA);

return 0;

}


But when I run main I get:

Box collision with Box
Sphere collision with Box
Box collision with Box
Sphere collision with Sphere
Sphere collision with Box


What goes on in the last two calls?
 
A

Andrey Tarasevich

saneman said:
...
class Box : public geometry_type
{
public :
Box() {}

virtual void haps(geometry_type* other)
{
other->collideWith(this);
}

virtual void collideWith(Sphere* other) {
std::cout << "Sphere collision with Sphere" << std::endl;

Huh? This should be "Box collision with Sphere", shouldn't it?
}

virtual void collideWith(Box* other) {
std::cout << "Box collision with Box" << std::endl;
}


};

class Sphere : public geometry_type
{
public :
Sphere() {}

virtual void haps(geometry_type* other)
{
other->collideWith(this);
}

virtual void collideWith(Sphere* other) {
std::cout << "Sphere collision with Sphere" << std::endl;
}

virtual void collideWith(Box* other) {
std::cout << "Sphere collision with Box" << std::endl;
}


};


void narrow_phase(geometry_type* G1, geometry_type* G2)
{
G1->haps(G2);
}

int main()
{
Box* BoxA = new Box();
Sphere* SphereA = new Sphere();

BoxA->collideWith(BoxA);
SphereA->collideWith(BoxA);

// Should print box collide with box.
narrow_phase(BoxA, BoxA);

// Should print sphere collide with box.
narrow_phase(SphereA, BoxA);

No. Your 'haps' method essentially "swaps" the objects involved in the
collision (take a closer look at it): 'G1' from 'narrow_phase' becomes
'this' in 'haps'. So, it should print "Box collision with Sphere". And
it will, if you fix the error mentioned above.
// Should print box collide with sphere.
narrow_phase(BoxA, SphereA);

Again, no. For the very same reason it should print "Sphere collision
with Box". And that exactly what it prints.
return 0;

}


But when I run main I get:

Box collision with Box
Sphere collision with Box
Box collision with Box
Sphere collision with Sphere
Sphere collision with Box


What goes on in the last two calls?

See above.
 
H

hurcan solter

I am trying to use double dispatch in the below code:

#include <iostream>

class Box;
class Sphere;


class geometry_type
{
public:
virtual void haps(geometry_type* other)=0;
virtual void collideWith(Box* other)=0;
virtual void collideWith(Sphere* other) = 0;
};

class Box : public geometry_type
{
public :
Box() {}

virtual void haps(geometry_type* other)
{
other->collideWith(this);
}

virtual void collideWith(Sphere* other) {
std::cout << "Sphere collision with Sphere" << std::endl;
}
Here is a typo;it should read' Box collision with sphere'

virtual void collideWith(Box* other) {
std::cout << "Box collision with Box" << std::endl;
}


};

class Sphere : public geometry_type
{
public :
Sphere() {}

virtual void haps(geometry_type* other)
{
other->collideWith(this);
}

virtual void collideWith(Sphere* other) {
std::cout << "Sphere collision with Sphere" << std::endl;
}

virtual void collideWith(Box* other) {
std::cout << "Sphere collision with Box" << std::endl;
}


};


void narrow_phase(geometry_type* G1, geometry_type* G2)
{
G1->haps(G2);
}

int main()
{
Box* BoxA = new Box();
Sphere* SphereA = new Sphere();

BoxA->collideWith(BoxA);
SphereA->collideWith(BoxA);

// Should print box collide with box.
narrow_phase(BoxA, BoxA);

// Should print sphere collide with box.
narrow_phase(SphereA, BoxA);

// Should print box collide with sphere.
narrow_phase(BoxA, SphereA);

return 0;

}


But when I run main I get:

Box collision with Box
Sphere collision with Box
Box collision with Box
Sphere collision with Sphere
Sphere collision with Box


What goes on in the last two calls?

Last one is correct, you switch the parameters
inside the haps. Late there :)
 
D

Daniel Pitts

saneman said:
I am trying to use double dispatch in the below code:

#include <iostream>

class Box;
class Sphere;


class geometry_type
{
public:
virtual void haps(geometry_type* other)=0;
virtual void collideWith(Box* other)=0;
virtual void collideWith(Sphere* other) = 0;
};

class Box : public geometry_type
{
public :
Box() {}

virtual void haps(geometry_type* other)
{
other->collideWith(this);
}

virtual void collideWith(Sphere* other) {
std::cout << "Sphere collision with Sphere" << std::endl;
}

virtual void collideWith(Box* other) {
std::cout << "Box collision with Box" << std::endl;
}


};

class Sphere : public geometry_type
{
public :
Sphere() {}

virtual void haps(geometry_type* other)
{
other->collideWith(this);
}

virtual void collideWith(Sphere* other) {
std::cout << "Sphere collision with Sphere" << std::endl;
}

virtual void collideWith(Box* other) {
std::cout << "Sphere collision with Box" << std::endl;
}


};


void narrow_phase(geometry_type* G1, geometry_type* G2)
{
G1->haps(G2);
}

int main()
{
Box* BoxA = new Box();
Sphere* SphereA = new Sphere();

BoxA->collideWith(BoxA);
SphereA->collideWith(BoxA);

// Should print box collide with box.
narrow_phase(BoxA, BoxA);

// Should print sphere collide with box.
narrow_phase(SphereA, BoxA);

// Should print box collide with sphere.
narrow_phase(BoxA, SphereA);

return 0;

}


But when I run main I get:

Box collision with Box
Sphere collision with Box
Box collision with Box
Sphere collision with Sphere
Sphere collision with Box


What goes on in the last two calls?
Because your Box::collideWith(Sphere*) has a bug in it. Has nothing to
do with your double dispatch, which appears to be working perfectly.
 
S

saneman

hurcan said:
Here is a typo;it should read' Box collision with sphere'



Last one is correct, you switch the parameters
inside the haps. Late there :)

thanks! Yes it was a bit late :) I am wondering why the baseclass
should be declared as abstract. I have tried to change it to:


class geometry_type
{
public:

virtual void haps(geometry_type* other)
{
other->collideWith(this);
}


virtual void collideWith(Box* other)
{
std::cout << "Box collision" << std::endl;
}

virtual void collideWith(Sphere* other)
{
std::cout << "Sphere collision" << std::endl;
}





// virtual void haps(geometry_type* other)=0;
// virtual void collideWith(Box* other)=0;
// virtual void collideWith(Sphere* other) = 0;

};

But then I get:


test2.cpp: In member function ‘virtual void
geometry_type::haps(geometry_type*)’:
test2.cpp:16: error: no matching function for call to
‘geometry_type::collideWith(geometry_type* const)’
test2.cpp:19: note: candidates are: virtual void
geometry_type::collideWith(Box*)
test2.cpp:24: note: virtual void
geometry_type::collideWith(Sphere*)


Is there some rule that the baseclass must be abstract?
 
J

James Kanze

hurcan solter wrote:
thanks! Yes it was a bit late :) I am wondering why the baseclass
should be declared as abstract.

It doesn't have to be.
I have tried to change it to:

class geometry_type
{
public:
virtual void haps(geometry_type* other)
{
other->collideWith(this);

And what should this call? Function overload resolution only
concerns static types.
virtual void collideWith(Box* other)
{
std::cout << "Box collision" << std::endl;
}
virtual void collideWith(Sphere* other)
{
std::cout << "Sphere collision" << std::endl;
}
// virtual void haps(geometry_type* other)=0;
// virtual void collideWith(Box* other)=0;
// virtual void collideWith(Sphere* other) = 0;
};
But then I get:

test2.cpp: In member function ?virtual void
geometry_type::haps(geometry_type*)?:
test2.cpp:16: error: no matching function for call to
?geometry_type::collideWith(geometry_type* const)?
test2.cpp:19: note: candidates are: virtual void
geometry_type::collideWith(Box*)
test2.cpp:24: note: virtual void
geometry_type::collideWith(Sphere*)
Is there some rule that the baseclass must be abstract?

No. But there is a rule that when you call a function, one of
the function found with name lookup must be callable with the
static types of your arguments.

Think about it for a moment. What you're asking for is
basically double dispatch. Or at least, dispatch on the dynamic
type of an argument, not on the object the function is called
on.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,225
Members
46,815
Latest member
treekmostly22

Latest Threads

Top