Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何模拟方法模板的虚拟性_C++_Templates_Polymorphism - Fatal编程技术网

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>
以下是wikipedia文章中的“简单”方法供参考(不太简单的方法更适合于大量派生类型):

//通过动态\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
        }
    }
}