如何模拟方法模板的虚拟性
我有一个类层次结构,我想介绍一个方法模板,它的行为就像虚拟一样。例如一个简单的层次结构:如何模拟方法模板的虚拟性
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();
我知道我可以通过typeid(a)
存储在a
类型。当我知道该类型时,如何动态调用正确的B::method
?我可能有这样的情况:
if(typeid(*a)==typeid(B))
static_cast<B*>(a)->method(params);
但我想,以避免类似的情况。我正在考虑创建一个std::map
作为关键字typeid
,但是我会把它作为一个价值?
如您所知,由于虚拟函数的整体属于类类型的一部分并且必须事先知道,因此不能为虚拟函数提供模板。这排除了任何简单的“任意重写”。
如果它是一个选项,你可以使类的模板参数部分:
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) { }
// ...
};
是否有任何共同的代码,你可以提取和虚拟?
class A {
virtual ~A() {}
template<typename T>
void method(T &t)
{
...
DoSomeWork();
...
}
virtual void DoSomeWork() {}
};
class B : public A {
virtual void DoSomeWork() {}
};
纯粹的常识驱动!这有帮助,谢谢! – Arun
您可以使用“奇异递归模板模式” 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);
在这种情况下不会有基类,所以你不能存储这些类。在一个向量中,因为A类是一个模板。但是,您可以从一个常见的ABase继承,但在这种情况下,您无法从Base中访问该方法。 –
@工业抗抑郁药是的,这种方法有明显的缺点,例如不能在容器中存储不同的派生类型,但这仍然是一个有用的设计模式。 – Alan
糟糕。最初回答at the wrong question - 不错啊,在另一个问题
经过一番思考我认识到了这个经典的多方法要求,即一个方法,它能将基于多个参数的运行时类型 。通常的虚拟功能是single dispatch
比较(和他们派遣的类型this
只)。
请参考以下:
- 安德烈Alexandrescu的写上实施使用泛型在 '现代C++设计'
- Chapter 11: "Multimethods"多方法(吗?C++精液比特) - 它实现了基本的多方法,使它们成为对数(使用有序的类型列表),然后一直到恒定时间的多方法。相当强大的东西!
- 一个codeproject article,似乎刚才这样的实现:
- 没有用型投下任何种类的(动态,静态,重新诠释,const或C型)
- 没有用的RTTI ;
- 不使用预处理器;
- 强型安全;
- 单独编译;
- 多方法执行的恒定时间;
- 在multimethod调用期间没有动态内存分配(通过new或malloc);
- 不使用非标准库;
- 只使用标准的C++功能。
- C++ Open Method Compiler,彼得Pirkelbauer,尤里Solodkyy和Bjarne的Stroustrup的
- 洛基图书馆有A MultipleDispatcher
*有与C++在多分派的例子相当不错simple write-up。
这里是从*文章供参考 '简单' 的方法(在以下简单的方法扩展为较大数量的派生类型的更好):
// 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
}
}
}
我不能那样做。我真的需要一个方法模板。 –
@JurajBlaho:我又增加了一个想法。 –
@JurajBlaho:恩,[使成员模板虚拟只是不能在C + +](http://*.com/questions/2354210/can-a-member-function-template-be-virtual/2354671#2354671) ,所以你将不得不重新考虑你的方法,并对语言的限制做出一些让步。 – sbi