如何实现函数Foo
以分派到正确的函数?
以下代码重现了该问题,并在评论中获得了一些其他信息。
#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;
}
答案 0 :(得分:3)
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");
}
这是有效的,因为如果类型不正确,dynamic_cast会返回nullptr。上面的代码是C ++ 11,但如果用明显的代码替换“auto”类型,它将是C ++ 98(如果有很多情况,我会使用宏)。
答案 1 :(得分:3)
对于OO,只有派生类本身知道它是谁,以及该怎么做。
#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;
}
答案 2 :(得分:3)
#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;
}
如果声明一个中间类,则可以使用多态而不更改Base
。您只需要执行一个dynamic_cast<>
,但每次要使用新类型作为模板参数时都不必更改Foo()
,因此您的代码必须遵守开放/封闭原则。 / p>
答案 3 :(得分:1)
如何调用正确的DoSomething方法?
更好的方法是利用多态在C ++中的工作方式,而不是根据强制转换编写一些调度函数。几个选择:
DoSomething
声明为类Base
中的公共纯虚方法。该模板将提供实施。DoSomething
定义为类Base
中的公共非虚方法。该实现调用一些私有的纯虚方法。该模板再次提供了此虚拟方法的实现。