As stefaanv says, this can be achieved with double dispatch with some extra plumbing:
#include <iostream>
class Derived1;
class Derived2;
class ParamType
{
public:
virtual void invertFunc (const Derived1& deriv) const = 0;
virtual void invertFunc (const Derived2& deriv) const = 0;
};
class DerivedParamType1;
class DerivedParamType2;
class Base
{
public:
virtual void func (const ParamType& param) const = 0;
virtual void func (const DerivedParamType1& param) const
{
throw std::runtime_error ("Can not accept DerivedParamType1");
}
virtual void func (const DerivedParamType2& param) const
{
throw std::runtime_error ("Can not accept DerivedParamType2");
}
};
class Derived1 : public Base
{
public:
void func (const ParamType& param) const
{
param.invertFunc (*this);
}
void func (const DerivedParamType1& param) const
{
std::cout << "Derived1::func (DerivedParamType1)" << std::endl;
}
};
class Derived2 : public Base
{
public:
void func (const ParamType& param) const
{
param.invertFunc (*this);
}
void func (const DerivedParamType2& param) const
{
std::cout << "Derived2::func (DerivedParamType2)" << std::endl;
}
};
class DerivedParamType1 : public ParamType
{
public:
void invertFunc (const Derived1& deriv) const
{
deriv.func (*this);
}
void invertFunc (const Derived2& deriv) const
{
deriv.func (*this);
}
};
class DerivedParamType2 : public ParamType
{
public:
void invertFunc (const Derived1& deriv) const
{
deriv.func (*this);
}
void invertFunc (const Derived2& deriv) const
{
deriv.func (*this);
}
};
int main (int argc, char* argv[])
{
ParamType* paramType = new DerivedParamType1;
Base* deriv = new Derived1;
deriv->func (*paramType);
return 0;
}
Note that there's actually 3 jumps (dispatches) here as you asked for Base::func(ParamType)
to call Derived1::func(DerivedParamType1)
. If you are happy with either:
Base::func(ParamType)
calls DerivedParamType1::func(Derived1)
or
ParamType::func(Base)
calls Derived1::func(DerivedParamType1)
then you can eliminate one of the jumps.