Why does double dispatch not work in C++? - c++

#include<iostream.h>
#include<conio.h>
using namespace std;
class SpaceShip {};
class GiantSpaceShip : public SpaceShip {};
class Asteroid {
public:
virtual void CollideWith(SpaceShip *) {
cout << "Asteroid hit a SpaceShip" << endl;
}
virtual void CollideWith(GiantSpaceShip *) {
cout << "Asteroid hit a GiantSpaceShip" << endl;
}
};
class ExplodingAsteroid : public Asteroid {
public:
virtual void CollideWith(SpaceShip *) {
cout << "ExplodingAsteroid hit a SpaceShip" << endl;
}
virtual void CollideWith(GiantSpaceShip *) {
cout << "ExplodingAsteroid hit a GiantSpaceShip" << endl;
}
};
int main()
{
SpaceShip * s = new GiantSpaceShip();
Asteroid * a = new ExplodingAsteroid();
a->CollideWith(s);
getch();
return 0;
}
How can I enable double dispatch in C++?

This is not single dispatch but double dispatch: you want the method to depend both on the actual/real type of the object it is invoked on, and on the actual/real type of the argument.
This issue can be solved by the Visitor design pattern.

Luc is right on with using the Visitor pattern, I'm just expanding on that by giving an example of how you could do it.
#include <iostream>
#include <conio.h>
using namespace std;
class SpaceObject;
class SpaceShip;
class GiantSpaceShip;
class Asteroid;
class ExplodingAsteroid;
class SpaceObject {
public:
virtual void CollideWith(SpaceObject*) {}
virtual void CollideWith(SpaceShip*) {}
virtual void CollideWith(GiantSpaceShip*) {}
virtual void CollideWith(Asteroid*) {}
virtual void CollideWith(ExplodingAsteroid*) {}
};
class Asteroid : public SpaceObject {
public:
virtual void CollideWith(SpaceObject* o) { o->CollideWith(this); }
virtual void CollideWith(SpaceShip *) { cout << "Asteroid hit a SpaceShip" << endl; }
virtual void CollideWith(GiantSpaceShip *) { cout << "Asteroid hit a GiantSpaceShip" << endl; }
};
class ExplodingAsteroid : public Asteroid {
public:
virtual void CollideWith(SpaceObject* o) { o->CollideWith(this); }
virtual void CollideWith(SpaceShip *) { cout << "ExplodingAsteroid hit a SpaceShip" << endl; }
virtual void CollideWith(GiantSpaceShip *) { cout << "ExplodingAsteroid hit a GiantSpaceShip" << endl; }
};
class SpaceShip : public SpaceObject {
public:
virtual void CollideWith(SpaceObject* o) { o->CollideWith(this); }
virtual void CollideWith(Asteroid* o) { o->Asteroid::CollideWith(this); }
virtual void CollideWith(ExplodingAsteroid* o) { o->ExplodingAsteroid::CollideWith(this); }
};
class GiantSpaceShip : public SpaceShip {
public:
virtual void CollideWith(SpaceObject* o) { o->CollideWith(this); }
virtual void CollideWith(Asteroid* o) { o->Asteroid::CollideWith(this); }
virtual void CollideWith(ExplodingAsteroid* o) { o->ExplodingAsteroid::CollideWith(this); }
};
int main()
{
SpaceObject* s = new GiantSpaceShip();
SpaceObject* a = new ExplodingAsteroid();
a->CollideWith(s);
getch();
return 0;
}

Related

How to operate on only one type of derived class when working with multiple derived classes?

I have 1 base class, Item, and 3 derived classes: CD, Book, & List.
I figured out how to print out and add Item objects, regardless of whether it's a Book or CD, in a vector within a List object. But I can't figure out how to print only Books or only CDs. I can't make any mentions of a CD or Book class in the List class, and I can't move the bool isBook or isCD members to the base class.
class Item
{
protected:
string name;
int id;
public:
//pure virtual methods (ex: virtual bool isID(int);
};
class CD: public Item
{
private:
bool isCD;
public:
//defining virtual methods from base class for class specific operations
virtual string format() { return "Artist: " + name }
};
class Book: public Item
{
private:
bool isBook;
public:
//defining virtual methods from base class for class specific operations
virtual string format() { return "Author: " + name }
};
class List: public Item
{
private:
vector<Item*> holdings;
public:
void Add(Item &adding) {} // already figured out
void printAll() // print all objects in vector regardless of type Book or CD
{
for(auto &i: holdings)
cout << i->format() << '\n';
}
void printBooks(){}
void PrintCDs(){}
}
You don't need the isCD and isBook boolean members in each class. You can use dynamic_cast instead, eg:
class List: public Item
{
private:
vector<Item*> holdings;
public:
...
void printAll() const
{
for(auto *i: holdings)
cout << i->format() << '\n';
}
void printBooks() const
{
for(auto *i: holdings)
{
if (Book *b = dynamic_cast<Book*>(i))
cout << b->format() << '\n';
}
}
void PrintCDs() const
{
for(auto *i: holdings)
{
if (CD *c = dynamic_cast<CD*>(i))
cout << c->format() << '\n';
}
}
};
If you don't want to use this approach, then you can use some additional virtual methods instead, eg:
class Item
{
...
public:
...
virtual bool isBook() const { return false; }
virtual bool isCD() const { return false; }
};
class CD: public Item
{
...
public:
...
bool isCD() const override { return true; }
};
class Book: public Item
{
...
public:
...
bool isBook() const override { return true; }
};
class List: public Item
{
private:
vector<Item*> holdings;
public:
...
void printAll() const
{
for(auto *i: holdings)
cout << i->format() << '\n';
}
void printBooks() const
{
for(auto *i: holdings)
{
if (i->isBook())
cout << i->format() << '\n';
}
}
void PrintCDs() const
{
for(auto *i: holdings)
{
if (i->isCD())
cout << i->format() << '\n';
}
}
};
Alternatively:
enum ItemType { itCD, itBook };
class Item
{
...
public:
...
virtual ItemType getType() const = 0;
};
class CD: public Item
{
...
public:
...
ItemType getType() const override { return itCD; }
};
class Book: public Item
{
...
public:
...
ItemType getType() const override { return itBook; }
};
class List: public Item
{
private:
vector<Item*> holdings;
public:
...
void printAll() const
{
for(auto *i: holdings)
cout << i->format() << '\n';
}
void printBooks() const
{
for(auto *i: holdings)
{
if (i->getType() == itBook)
cout << i->format() << '\n';
}
}
void PrintCDs() const
{
for(auto *i: holdings)
{
if (i->getType() == itCD)
cout << i->format() << '\n';
}
}
};

When apply observer pattern an error occured

I have the following code:
class ISubscriber;
class News {
public:
float getVersion() { return this->version; }
void setVersion(float state) { this->version= state; this->notifyAllSubscribers(); }
void attach(ISubscriber *observer) { this->subscribers.push_back(observer); }
void notifyAllSubscribers() {
for (vector<ISubscriber*>::iterator it = subscribers.begin(); it != subscribers.end(); it++){
(*(*it)).update();
}
}
private:
vector<ISubscriber*> subscribers;
float version;
};
class ISubscriber {
public:
News *news;
virtual void update() = 0;
};
class Subscriber1 : public ISubscriber {
public:
Subscriber1(News *news) { this->news = news; this->news->attach(this); }
void update() override { cout << "Subscriber1: A new version of the newspaper has been launched (v" << this->news->getVersion() << ")" << endl; }
};
class Subscriber2 : public ISubscriber {
public:
Subscriber2(News *news) { this->news = news; this->news->attach(this); }
void update() override { cout << "Subscriber2: A new version of the newspaper has been launched (v" << this->news->getVersion() << ")" << endl; }
};
int main(int argc, char *argv[]) {
News newspaper;
newspaper.setVersion(2.1f);
Subscriber1 sb1(&newspaper);
Subscriber2 sb2(&newspaper);
return 0;
}
But strange errors happened:
The first error points to this code (*(*it)).update(); in news class.
Why that errors happened, what's the reason?
(*(*it)).update(); requires the type ISubscriber to be complete, just the forward declaration is not enough.
You could move the defnition of ISubscriber before the one of News, and give a forward declaration of News before that.
class News;
class ISubscriber {
public:
News *news;
virtual void update() = 0;
};
class News {
public:
float getVersion() { return this->version; }
void setVersion(float state) { this->version= state; this->notifyAllSubscribers(); }
void attach(ISubscriber *observer) { this->subscribers.push_back(observer); }
void notifyAllSubscribers() {
for (vector<ISubscriber*>::iterator it = subscribers.begin(); it != subscribers.end(); it++){
(*(*it)).update();
}
}
private:
vector<ISubscriber*> subscribers;
float version;
};

Can't create virtual class in CLR C++

I'm working around simple program In MSVS 2010 which is Windows form application, and suddenly reached really weird problem: I can't create virtual functions in class.
Here is the code:
#pragma once;
#include <string>
using namespace std;
using namespace System;
class Reptile
{
private:
char *diet;
string title;
double weight;
int lifespan;
char sex;
public:
char* getDiet();
bool setDiet(char* newDiet);
string getTitle();
bool setTitle(string newTitle);
double getWeight();
bool setWeight(double newWeight);
int getLifespan();
bool setLifeSpan(int newLifespan);
char getSex();
void setSex(char newSex);
virtual void Show(void);
virtual void Voice(void);
~Reptile();
Reptile(); };
It throws error like this:
Reptile.obj : error LNK2028: unresolved token (0A00000E) "public: virtual void __clrcall Reptile::Voice(void)" (?Voice#Reptile##$$FUAMXXZ) referenced in function "void __clrcall dynamic initializer for 'const Reptile::vftable'''(void)" (???__E??_7Reptile##6B###YMXXZ#?A0xc2bc2ccd##$$FYMXXZ)
I really cant figure out how to handle it because I'm not very familiar with clr and stuff.
Include bodies for Show(), Voice(), Reptile() and ~Reptile() and it will work. Like that:
virtual void Show() {};
virtual void Voice() {};
Reptile() {};
~Reptile() {};
Below you can see a working example:
#include <iostream>
#include <string>
using namespace std;
class Reptile
{
private:
char* diet;
string title;
double weight;
int lifespan;
char* sex;
public:
char* getDiet()
{
return diet;
};
void setDiet(char* newDiet)
{
diet = newDiet;
};
string getTitle()
{
return title;
}
void setTitle(string newTitle)
{
title = newTitle;
}
double getWeight()
{
return weight;
}
double setWeight(double newWeight)
{
weight = newWeight;
}
int getLifespan()
{
return lifespan;
}
void setLifeSpan(int newLifespan)
{
lifespan = newLifespan;
}
char* getSex()
{
return sex;
}
void setSex(char* newSex)
{
sex = newSex;
}
// make them pure virtual functions
virtual void Show() = 0;
virtual void Voice() = 0;
Reptile() {};
~Reptile() {};
};
class Dinosaur : public Reptile
{
public:
virtual void Show()
{
cout << "Showing dino" << endl;
}
virtual void Voice()
{
cout << "Rawrrrrr!" << endl;
}
};
int main()
{
Reptile *dino1 = new Dinosaur();
dino1->setSex("M");
dino1->setTitle("T-Rex");
cout << "Type: " << dino1->getTitle() << endl;
cout << "Sex: " << dino1->getSex() << endl;
dino1->Show();
dino1->Voice();
delete dino1;
}

Inheritance , how can i make two classes share the same base class contents?

I have an Abstract Class operations that inherits from VAR Class , which then all the operations derived class(out,sleep,Add) inherit from the operations class. FSM Class inherits from Var also, so That I want one instance of VAR class inside my program.
I am trying to make vector < pair< string, int>> var as a shared data between the FSM class and the Operations class and its deviates . I initialized the var in the main through the FSM class .
Each time we call the exist function in VAR through Class operation , it returns it doesn't exits cause it is empty ! How can I overcome this?
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
using namespace std;
class VAR
{
public:
vector<pair<string, int>> var;
VAR()
{
cout << "created VAR" << endl;
}
~VAR(){ cout << "Destrioed VAR" << endl; }
void createVar(string x,int y)
{
pair<string, int>t;
t.first = x;
t.second = y;
var.push_back(t);
}
int getVarValue(string x)
{
for (int i = 0; i<var.size(); i++)
{
if (var[i].first == x)
{
return var[i].second;
}
}
}
void setVarValue(string& x, int y)
{
for (int i = 0; i<var.size(); i++)
{
if (var[i].first == x)
{
var[i].second = y;
i = var.size();
}
}
}
bool exits(string& name)
{
for (int i = 0; i<var.size(); i++)
{
if (var[i].first == name)
return true;
}
return false;
}
};
class operations : virtual public VAR
{
public:
operations()
{
cout << "operations created" << endl;
}
~operations()
{
cout << "operations Destroied" << endl;
}
void virtual excute() = 0;
};
class Out :public virtual operations
{
public:
string s;
Out(string xx = "") :s(xx)
{
cout << "Out created" << endl;
}
~Out()
{
cout << "Out Destroied" << endl;
}
void virtual excute()
{
cout << "out Class" << endl;
if (exits(s))
cout<<"it never reach here, WHY !"<<endl;
}
};
class Add :public virtual operations
{
public:
string s;
Add(string ss = "") :s(ss)
{
cout << "ADD created" << endl;
}
~Add()
{
cout << "Add Destroied" << endl;
}
void virtual excute()
{
string ex1 = s.substr(s.find('=') + 1, s.find('+')), ex2 = s.substr(s.find('+') + 1);
if (exits(ex1))
cout<<"it never reach here, WHY !"<<endl;
else
result = atoi(ex1.c_str());
if (exits(ex2))
cout<<"it never reach here, WHY !"<<endl;
}
};
class state
{
public:
vector<operations*> instructionList;
string name;
void exec_all()
{
for (int x = 0; x < instructionList.size(); x++)
instructionList[x]->excute();
}
};
class transition
{
public:
vector < pair<state, vector<pair<state, int>>>> trans;
static int currentState;
};
class FSM :public virtual VAR, public virtual transition
{
public:
FSM()
{
cout << "FSM" << endl;
}
void intialize()
{
createVar("X", 1);
createVar("Y", 5);
}
};
void main()
{
FSM x;
pair<state, vector<pair<state, int>>> p1;
pair<state, int>p2;
x.intialize();
p2.first.name = "b";
p2.second = 3;
p1.first.name = "a";
p1.second.push_back(p2);
x.trans.push_back(p1);
x.trans[0].first.instructionList.push_back(new Add("X=X+Y"));
x.trans[0].first.instructionList.push_back(new Out("X"));
x.trans[0].first.exec_all();//wrong output cause exist() returns false
}
A minimal complete example looks something like this:
#include <iostream>
using namespace std;
class VAR
{
public:
int var;
virtual ~VAR()
{}
void setVar(int n)
{var=n;}
};
class Out :public VAR
{};
class FSM :public VAR
{};
int main()
{
FSM x;
x.setVar(5);
Out OP;
if (x.var==OP.var)
cout<<"it reaches here now" << endl;
else
cout << "it fails" << endl;
return(0);
}
And one way to fix it is like this:
class VAR
{
public:
static int var;
int var;
virtual ~VAR()
{}
void setVar(int n)
{var=n;}
};
int VAR::var=0;

in base class, how to define a container to contain function obj which can be any func of derived class?

I want to define a container in the base class, which contains function obj or anything that can make my purpose happen. These function obj can call derived classes' functions. they all take same parameters.
#include <vector>
#include <functional>
#include <iostream>
class Foo {
Foo() {}
virtual ~Foo(){}
virtual void init()
{ registerCallback(0, &Foo::print_ori ); }
void print_ori(int i) const { std::cout << i << '\n'; }
void registerCallback(int key, ??? cb ) // NOT SURE HOW TO DEFINE THIS
{
callbacks[key] = cb;
}
void runCallbacks(int key, int n)
{
auto i = callbacks.find(key);
if (i != callbacks.end()) {
(*i)(*this, n);
}
}
std::map<int, std::function<void(const Foo&, int) > > callbacks; // obviously, it's wrong. how to fix it?
};
struct Foo2 : public Foo {
Foo2(int num) : Foo(num) {}
virtual void init()
{
Foo::init();
registerCallback(11, &Foo2::print1 );
registerCallback(12, &Foo2::print2 );
}
void print1(int i) const { std::cout << " - Foo2.p1 - " << i << endl; }
void print2(int i) const { std::cout << " - Foo2.p2 - " << i << endl; }
};
int main()
{
Foo* obj = new Foo2();
obj->init();
obj->runCallbacks(12, 456);
}
Here's a way to achieve what your code looks like it's trying to do, without using function pointers:
class Foo {
Foo() {}
virtual ~Foo(){}
void print_ori(int i) const { std::cout << i << '\n'; }
virtual void do_runCallbacks(int v)
{
}
void runCallbacks()
{
print_ori(3)
do_runCallBacks(3);
}
};
struct Foo2 : public Foo {
Foo2(int num) : Foo(num) {}
void do_runcallbacks(int v)
{
print1(v);
print2(v);
}
void print1(int i) const { std::cout << " - Foo2.p1 - " << i << endl; }
void print2(int i) const { std::cout << " - Foo2.p2 - " << i << endl; }
};
int main()
{
Foo* obj = new Foo2();
obj->runCallbacks();
}
Now, there may well be reasons to do this completely differently, but I don't see why you should need both virtual functions and inheritance, AND function objects/function pointers. That seems quite wrong to me ("smells bad")
Edit:
Here's something I came up with, that solves the type of problem you describe after edits of the original question.
#include <iostream>
#include <map>
using namespace std;
class event_interface
{
public:
virtual void action(int n) = 0;
};
class event_manager
{
public:
event_manager(int n) : num(n) {}
void register_event(int key, event_interface *eh)
{
handlers[key] = eh;
}
void callback(int key)
{
auto h = handlers.find(key);
if (h != handlers.end())
{
h->second->action(num);
}
}
private:
map<int, event_interface *> handlers;
int num;
};
class handler1 : public event_interface
{
public:
void action(int n) { cout << "in handler1::action. n=" << n << endl; }
};
class handler2 : public event_interface
{
public:
handler2(int n) : data(n) {}
void action(int n)
{
cout << "in handler2::action. n=" << n
<< " data = " << data << endl;
}
private:
int data;
};
class multihandler
{
private:
class handler3: public event_interface
{
public:
void action(int n) { cout << "in handler3::action. n=" << n << endl; }
};
class handler4: public event_interface
{
public:
handler4(multihandler *m) : mh(m) {}
void action(int n)
{
cout << "in handler4::action. n=" << n
<< " data = " << mh->data << endl;
}
private:
multihandler* mh;
};
public:
multihandler(event_manager& em) : h4(this)
{
em.register_event(62, &h3);
em.register_event(63, &h4);
data = 42;
}
private:
handler3 h3;
handler4 h4;
int data;
};
int main()
{
event_manager mgr(3);
handler1 h1;
handler2 h2(77);
multihandler mh(mgr);
mgr.register_event(12, &h1);
mgr.register_event(13, &h2);
int evts[] = { 12, 63, 62, 13, 18 };
for(auto i : evts)
{
cout << "Event: " << i << endl;
mgr.callback(i);
}
}