C++ 如何模拟方法模板的虚拟性
我有一个类层次结构,我想在其中引入一个方法模板,它的行为就像是虚拟的一样。例如,一个简单的层次结构:C++ 如何模拟方法模板的虚拟性,c++,templates,polymorphism,C++,Templates,Polymorphism,我有一个类层次结构,我想在其中引入一个方法模板,它的行为就像是虚拟的一样。例如,一个简单的层次结构: class A { virtual ~A() {} template<typename T> void method(T &t) {} }; class B : public A { template<typename T> void method(T &t) {} }; 我知道我可以通过typeid(a)获得存储在a中的类型。当
class A {
virtual ~A() {}
template<typename T>
void method(T &t) {}
};
class B : public A {
template<typename T>
void method(T &t) {}
};
我知道我可以通过typeid(a)
获得存储在a
中的类型。当我知道类型时,如何动态调用正确的B::方法
?我可能有这样的情况:
if(typeid(*a)==typeid(B))
static_cast<B*>(a)->method(params);
if(typeid(*a)=typeid(B))
静态(a)->方法(参数);
但我希望避免出现这样的情况。我在考虑创建一个
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
};
模板类别A
{
受保护的:
虚空法(T&);
};
模板类别B:公共A
{
虚空方法(T&);//重写
};
更复杂的方法可能会使用某些dispatcher对象:
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) { }
// ...
};
struct BaseDispatcher
{
虚拟~BaseDispatcher(){}
模板void调用(T&T){dynamic_cast(this)->method(T);}
};
结构ConcreteDispatcher:BaseDispatcher
{
模板无效法(T&);
};
甲级
{
公众:
显式A(BaseDispatcher*p=0):p_disp(p==0?新的BaseDispatcher:p){}
virtual~A(){delete p_disp;};
私人:
BaseDispatcher*p_disp;
模板无效方法(T&T){p_disp->call(T);}
};
B类:公共A
{
公众:
B():A(新调度程序){}
// ...
};
是否有可以提取并虚拟化的通用代码
class A {
virtual ~A() {}
template<typename T>
void method(T &t)
{
...
DoSomeWork();
...
}
virtual void DoSomeWork() {}
};
class B : public A {
virtual void DoSomeWork() {}
};
A类{
虚拟~A(){}
模板
空隙法(T&T)
{
...
DoSomeWork();
...
}
虚拟void DoSomeWork(){}
};
B类:公共A{
虚拟void DoSomeWork(){}
};
您可以使用“奇怪的重复模板模式”
使用此模式,基类将派生类类型作为模板参数,这意味着基类可以将自己强制转换为派生类型,以便调用派生类中的函数。它是一种虚拟函数的编译时实现,具有不必执行虚拟函数调用的额外好处
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) {}
};
模板
甲级{
公众:
虚拟~A(){}
模板
void方法(T&T){static_cast(*this.methodImpl(T);}
};
B类:公共A
{
A级朋友;
公众:
虚拟~B(){}
私人:
模板
void methodImpl(T&T){}
};
然后可以像这样使用它
int one = 1;
A<B> *a = new B();
a->method(one);
intone=1;
A*A=新的B();
方法(一);
我认为唯一的解决办法是
请参见本主题:
哦。最初的回答是——啊,好吧,在另一个问题上
经过一番思考,我认识到这是经典的多方法要求,即基于多个参数的运行时类型进行调度的方法。相比之下,通常的虚拟函数是单一分派
(并且它们只根据此
类型分派)
请参阅以下内容:
-
<> Andrei Alexandrescu在《现代C++设计》中用泛型实现多方法的C++(S+++?)
- -它实现了基本的多方法,使它们成为对数(使用有序的类型列表),然后一直到常数时间多方法。相当强大的东西李>
- 似乎只有这样一个实现:
- 不使用任何类型的类型转换(动态、静态、重新解释、常量或C样式)
- 不使用RTTI李>
- 不使用预处理器李>
- 强型安全李>
- 单独汇编李>
- 多方法执行的恒定时间李>
- 在多方法调用期间没有动态内存分配(通过new或malloc)李>
- 不使用非标准图书馆李>
仅使用标准的C++特征。
- 彼得·皮尔克鲍尔、尤里·索洛德基和比亚恩·斯特劳斯特鲁普
- 洛基图书馆 维基百科在C++中有很多关于多调度的例子。p>
//通过动态\u转换使用运行时类型比较的示例
结构物{
虚拟空间与(对象和其他对象)=0;
}
结构小行星:东西{
虚空与(事物和其他)碰撞{
//如果转换失败,指针类型的动态\u转换将返回NULL
//(对引用类型的动态_转换将在失败时引发异常)
if(小行星*小行星=动态投影(&O)){
//处理小行星碰撞
}else if(太空船*太空船=动态施法(&O)){
//处理小行星与宇宙飞船的碰撞
}否则{
//这里默认的冲突处理
}
}
}
结构宇宙飞船:东西{
虚空与(事物和其他)碰撞{
if(小行星*小行星=动态投影(&O)){
//处理太空船小行星碰撞
}else if(太空船*太空船=动态施法(&O)){
//处理飞船碰撞
}否则{
//这里默认的冲突处理
}
}
}
我不能那样做。我真的需要一个方法模板。@JurajBlaho:我添加了另一个想法。@JurajBlaho:那么,你必须重新考虑你的方法,并对语言的局限性做出一些让步。实际上,没关系,第二个想法不起作用。你仍然需要某种多态性,而这种多态性是无法模板化的。在这种情况下,没有基类,所以你不能将这些类存储在向量中,例如,因为类a是一个模板。但是你可以从一个普通的堕落中继承
int one = 1;
A<B> *a = new B();
a->method(one);
// 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
}
}
}