我有一个类层次结构,我想引入一个方法模板,就像它是虚拟的一样。例如,一个简单的层次结构:
class A {
virtual ~A() {}
template<typename T>
void method(T &t) {}
};
class B : public A {
template<typename T>
void method(T &t) {}
};
然后我创建对象B:
A *a = new B();
我知道我可以通过a
获取存储在typeid(a)
中的类型。当我知道类型时,如何动态调用正确的B::method
?我可能有这样的情况:
if(typeid(*a)==typeid(B))
static_cast<B*>(a)->method(params);
但我想避免出现这样的情况。我正在考虑创建一个以std::map
作为关键字的typeid
,但我会将其作为一个值?
答案 0 :(得分:6)
您可以使用“奇怪的重复模板模式” http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
使用此模式,基类将派生类类型作为模板参数,这意味着基类可以将自身强制转换为派生类型,以便在派生类中调用函数。它是虚拟函数的一种编译时实现,具有无需进行虚函数调用的额外好处。
template<typename DERIVED_TYPE>
class A {
public:
virtual ~A() {}
template<typename T>
void method(T &t) { static_cast<DERIVED_TYPE &>(*this).methodImpl<T>(t); }
};
class B : public A<B>
{
friend class A<B>;
public:
virtual ~B() {}
private:
template<typename T>
void methodImpl(T &t) {}
};
然后可以像这样使用......
int one = 1;
A<B> *a = new B();
a->method(one);
答案 1 :(得分:2)
您是否可以提取和制作虚拟的常用代码?
class A {
virtual ~A() {}
template<typename T>
void method(T &t)
{
...
DoSomeWork();
...
}
virtual void DoSomeWork() {}
};
class B : public A {
virtual void DoSomeWork() {}
};
答案 2 :(得分:1)
您可能知道,您不能拥有虚函数模板,因为整个虚函数都是类类型的一部分,必须事先知道。这排除了任何简单的“任意改写”。
如果是一个选项,您可以将模板参数作为该类的一部分:
template <typename T> class A
{
protected:
virtual void method(T &);
};
template <typename T> class B : public A<T>
{
virtual void method(T &); // overrides
};
更复杂的方法可能会使用一些调度程序对象:
struct BaseDispatcher
{
virtual ~BaseDispatcher() { }
template <typename T> void call(T & t) { dynamic_cast<void*>(this)->method(t); }
};
struct ConcreteDispatcher : BaseDispatcher
{
template <typename T> void method(T &);
};
class A
{
public:
explicit A(BaseDispatcher * p = 0) : p_disp(p == 0 ? new BaseDispatcher : p) { }
virtual ~A() { delete p_disp; };
private:
BaseDispatcher * p_disp;
template <typename T> void method(T & t) { p_disp->call(t); }
};
class B : public A
{
public:
B() : A(new ConcreteDispatcher) { }
// ...
};
答案 3 :(得分:0)
我认为唯一的解决方案是http://en.wikipedia.org/wiki/Visitor_pattern
答案 4 :(得分:0)
<子> 的糟糕即可。最初回答at the wrong question - 好吧,在另一个问题上
经过一番思考后,我认为这是经典的多方法要求,即根据多个参数的运行时类型进行调度的方法。通常的虚拟函数比较single dispatch
(并且它们仅针对 this
的类型进行调度。)
请参阅以下内容:
维基百科有一个很好的simple write-up,其中包含C ++中的多个调度的示例。
以下是维基百科文章中的“简单”方法供参考(对于大量派生类型,不太简单的方法可以更好地扩展):
<子> 子>
// Example using run time type comparison via dynamic_cast
struct Thing {
virtual void collideWith(Thing& other) = 0;
}
struct Asteroid : Thing {
void collideWith(Thing& other) {
// dynamic_cast to a pointer type returns NULL if the cast fails
// (dynamic_cast to a reference type would throw an exception on failure)
if (Asteroid* asteroid = dynamic_cast<Asteroid*>(&other)) {
// handle Asteroid-Asteroid collision
} else if (Spaceship* spaceship = dynamic_cast<Spaceship*>(&other)) {
// handle Asteroid-Spaceship collision
} else {
// default collision handling here
}
}
}
struct Spaceship : Thing {
void collideWith(Thing& other) {
if (Asteroid* asteroid = dynamic_cast<Asteroid*>(&other)) {
// handle Spaceship-Asteroid collision
} else if (Spaceship* spaceship = dynamic_cast<Spaceship*>(&other)) {
// handle Spaceship-Spaceship collision
} else {
// default collision handling here
}
}
}