Reputation: 11255
How could I implement function Foo
to dispatch to the correct function?
The following code reproduces the problem, and got some additional information in comments.
#include <string>
class Base
{
public:
virtual ~Base(){};
};
template<typename T>
class Derived : public Base
{};
void DoSomething(const Derived<std::string> &){};
void DoSomething(const Derived<int> &){};
void Foo(Base *test)
{
// How to call correct DoSomething method?
// (I can't change class Base, but I know that test points to some instance of class Derived)?
// if(test points to an instance of Derived<int>)
// call void DoSomething(const Derived<int> &){};
// else if(test points to an instance of Derived<std::string>)
// call void DoSomething(const Derived<std::string> &){};
}
int main(int argc, char* argv[])
{
Base *test = new Derived<int>;
Foo(test);
delete test;
return 0;
}
Upvotes: 2
Views: 356
Reputation: 181
As to the OO, only the derived class itself knows who it is, and what to do.
#include <string>
class Base {}
class Mid : public Base
{
public:
virtual void DoSomething() = 0;
};
template<typename T>
class Derived : public Mid
{
public:
virtual void DoSomething() {}
};
template<> void Derived<std::string>::DoSomething(){}
template<> void Derived<int>::DoSomething(){}
void Foo(Base *test)
{
dynamic_cast<Mid*>(test)->DoSomething(); //TODO check the return of dynamic_cast
}
int main(int argc, char* argv[])
{
Base *test = new Derived<int>;
Foo(test);
delete test;
return 0;
}
Upvotes: 3
Reputation: 2715
#include <string>
class Base
{};
class DerivedBase : public Base
{
public:
virtual void DoSomething() = 0;
};
template<typename T>
class Derived : public DerivedBase
{};
void Foo(Base *test)
{
if (auto* p = dynamic_cast<DerivedBase*>(test))
p->DoSomething();
else
throw runtime_error("oops");
}
int main(int argc, char* argv[])
{
Base *test = new Derived<int>;
Foo(test);
delete test;
return 0;
}
If you declare an intermediate class, you can use polymorphism without changing Base
. You only have to do one dynamic_cast<>
but you won't have to change Foo()
each time you want to use a new type as a template argument, thus having your code respect the Open/Closed Principle.
Upvotes: 3
Reputation: 33106
How to call correct DoSomething method?
It's much better is take advantage of how polymorphism works in C++ rather than to write some dispatch function based on casting. A couple of alternatives:
DoSomething
as a public pure virtual method in class Base
. The template will provide the implementation.DoSomething
as a public non-virtual method in class Base
. The implementation invokes some private pure virtual method. The template once again provides the implementation of this virtual method.Upvotes: 1
Reputation: 249093
void Foo(Base *test)
{
if (auto* p = dynamic_cast<Derived<int>*>(test))
DoSomething(*p);
else if (auto* p = dynamic_cast<Derived<string>*>(test))
DoSomething(*p);
else
throw runtime_error("oops");
}
This works because dynamic_cast returns nullptr if the type is not correct. The code above is C++11, but it would be C++98 if you replace the "auto" types with the obvious ones (I'd use a macro if there are lots of cases).
Upvotes: 3