Reputation:
Consider the following code:
class A {
public:
virtual ~A() {}
};
class AA : public A {
};
////////////////////////////////////////
class B {
public:
virtual void f(const A &a) {
// code for A
}
};
class BB : public B {
public:
virtual void f(const AA &a) {
// code for AA
}
};
////////////////////////////////////////
int main() {
A *a = new AA;
B *b = new BB;
b->f(*a);
}
Obviously, the vtables are constructed such that when the above is run, // code for A
is executed. I am looking for a way to be able to execute instead // code for AA
.
The motivation is that this is for a library of code where the end-user will often have to write classes of the form BB, and I would like the process to be as easy as possible (i.e. the user should not have to use RTTI to figure out what derived class of A they are dealing with). Any ideas (and voodoo from any version of the C++ standard) are appreciated.
Upvotes: 3
Views: 207
Reputation: 36802
This is horrible style but it seems you are under some tight constraints
#include <typeinfo>
// everything else unmodified
class BB : public B {
public:
virtual void f(const A& arg) override {
try { //try to convert to an AA&
const AA& a{dynamic_cast<const AA&>(arg)};
// code for AA
} catch (std::bad_cast) { // if it fails, pass it up to B::f as an A&
this->B::f(arg);
}
}
};
////////////////////////////////////////
int main() {
A *aa = new AA;
A *a = new A;
B *b = new BB;
b->f(*a); // code for A executed
b->f(*aa); // code for AA executed
}
as per Alan Stoke's comment, dynamic casting pointers is much faster when it fails, so you could alternatively use this if you expect failure regularly:
class BB : public B {
public:
virtual void f(const A& arg) override {
const AA* ap = dynamic_cast<const AA*>(&arg);
if (ap == nullptr) {
return this->B::f(arg);
}
const AA& a{*ap}; // get a reference, if you want to
// code for AA
}
};
Upvotes: 3
Reputation: 45654
You can use RTTI and explicitly doing your own dispatching for that.
Co-Variant types only work for return types unfortunately.
Example:
class B {
void f_base(const A &a) {
// code for A
}
public:
virtual void f(const A &a) {
f_base(a); // Moved the base case outside
// to isolate the dispatching mechanism.
}
};
class BB : public B {
public:
virtual void f(const A& a) {
const AA* pAA = dynamic_cast<const AA*>(&a);
if(pAA) {
f(*pAA);
return;
}
f_base(a);
}
void f(const AA &a) {
// code for AA
}
};
More discussion of this type of dispatch as well of nicer packaging with templates is demonstrated here: "type-switch" construct in C++11
Upvotes: 5
Reputation: 37950
You need something that resembles the mechanism that is known as double dispatch, which in C++ can only be implemented indirectly:
class A {
public:
virtual callF(B & b) {
b.f(this);
}
virtual callF(BB & b) {
b.f(this);
}
};
class AA : public A {
public:
virtual callF(B & b) {
b.f(this);
}
virtual callF(BB & b) {
b.f(this);
}
};
Upvotes: 3
Reputation: 4482
The concept you are looking for is called double dispatch. Read more about it on http://en.wikipedia.org/wiki/Double_dispatch
It is not built into C++ but there are various ways to emulate it. One of them being the visitor pattern also found in the above link.
However you'll probably find all approaches lacking of elegance because you need to introduce AA to B, BB to A, or use RTTI and casts.
Upvotes: 1