使用模板解析虚拟方法

时间:2014-08-17 19:56:11

标签: c++ templates visual-studio-2008 dispatch visitor-pattern

此问题涉及使用模板解析Dispatch模式中的虚拟成员 注意:这与StackOverflow 上已经提出的虚拟模板方法问题不同。 *

编辑1:更正了语法错误,添加了说明。

鉴于以下内容:

#include <string>
#include <iostream>

class Field_Interface
{
  public:
    virtual std::string  get_field_name(void) const = 0;
};

class Field_Integer : public Field_Interface
{
  public:
    std::string get_field_name(void) const
    { return "INT";}
};

class Field_String : public Field_Interface
{
  public:
    std::string get_field_name(void) const
    { return "VARCHAR";}
};

class Field_Double : public Field_Interface
{
  public:
    std::string get_field_name(void) const
    { return "DOUBLE";}
};


class Abstract_Visitor
{
  public:
  virtual void visit(const Field_Integer& fi) = 0;
  virtual void visit(const Field_String& fi) = 0;
  virtual void visit(const Field_Double& fi) = 0;
};

class Visitor_Name_Query_1 : public Abstract_Visitor
{
  public:
  template <class Field>
  void visit(const Field& f)
  {
      std::cout << "Field name is: "
                << f.get_field_name()
                << "\n";
  }
};

class Visitor_Name_Query_2 : public Abstract_Visitor
{
  public:
    void visit(const Field_Integer& fi)
    { print_field_name(fi); }

    void visit(const Field_String& fi)
    { print_field_name(fi); }

    void visit(const Field_Double& fi)
    { print_field_name(fi); }

  private:
    void print_field_name(const Field_Interface& fi)
    { 
        std::cout << "Field name is: "
                  << fi.get_field_name()
                  << "\n";
    }
};

int main(void)
{
    Visitor_Name_Query_1    q1;
    Field_Integer           fi;
    q1.visit(f1);
    return 0;
}

编译器说Visitor_Name_Query_1中的模板化方法没有解析Abstract_Visitor的抽象接口。

编辑2:来自g ++的结果

# g++ -o main.exe main.cpp
main.cpp: In function `int main()':
main.cpp:75: error: cannot declare variable `q1' to be of type `Visitor_Name_Query_1'
main.cpp:75: error:   because the following virtual functions are abstract:
main.cpp:35: error:  virtual void Abstract_Visitor::visit(const Field_Integer&)
main.cpp:36: error:  virtual void Abstract_Visitor::visit(const Field_String&)
main.cpp:37: error:  virtual void Abstract_Visitor::visit(const Field_Double&)
main.cpp:77: error: `f1' undeclared (first use this function)
main.cpp:77: error: (Each undeclared identifier is reported only once for each function it appears in.)

Visitor_Name_Query_1试图简化课程Visitor_Name_Query_2。当visit方法的数量增长超过简单数量(如5)时,维护变得乏味。这是template声明的原因。

使用其中一种字段类型展开模板时,声明与Visitor_Name_Query_2中的声明匹配。

那么为什么编译器生成说class Visitor_Name_Query_1是抽象的呢?

注意:我在Windows Vista上使用Visual Studio 2008。

* 其他帖子涉及使用模板创建虚拟方法声明。我使用模板创建实现抽象方法的函数。

3 个答案:

答案 0 :(得分:2)

  

那么为什么编译器生成说类Visitor_Name_Query_1是抽象的呢?

因为标准是这样说的。 §14.5.2[temp.mem] / p4:

  

成员函数模板的特化不会覆盖a   基类的虚函数。 [示例

class B {
    virtual void f(int);
};
class D : public B {
    template <class T> void f(T); // does not override B::f(int)
    void f(int i) { f<>(i); }     // overriding function that calls
                                  // the template instantiation
};
     

- 结束示例]

答案 1 :(得分:0)

您似乎确实希望Abstract_Visitor具有默认实现。如果您将template移到Abstract_Visitor,则可以让每个virtual访问者拥有默认实施。

class Abstract_Visitor
{
  template <class Field>
  void visit(const Field& f)
  {
      std::cout << "Field name is: "
                << f.get_field_name()
                << "\n";
  }
  public:
  virtual void visit(const Field_Integer& fi) { visit<>(fi); }
  virtual void visit(const Field_String& fi) { visit<>(fi); }
  virtual void visit(const Field_Double& fi) { visit<>(fi); }
};

答案 2 :(得分:0)

由于所有字段类型都有一个通用接口,您可以通过更改接口来简化问题:

class Abstract_Visitor
{
  public:
  virtual void visit(const Field_Interface& f) = 0;
};

class Visitor_Name_Query_3 : public Abstract_Visitor
{
  public:
  void visit(const Field_Interface& f)
  {
      std::cout << "Field name is: "
                << f.get_field_name()
                << "\n";
  }
};