代码之家  ›  专栏  ›  技术社区  ›  Thomas Matthews

使用模板解析虚拟方法

  •  -2
  • Thomas Matthews  · 技术社区  · 10 年前

    此问题涉及使用模板来解析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.)
    

    访问者名称查询_1 试图简化课堂 Visitor_Name_Query_2 。当 visit 方法超出了简单的数量(如5个),维护变得乏味。这就是为什么 template 公告

    使用其中一种字段类型展开模板时,声明与 访问者名称查询2 .

    那么为什么编译器生成这样的语句 class Visitor_Name_Query_1 是抽象的吗?

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

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

    3 回复  |  直到 10 年前
        1
  •  2
  •   T.C. Yksisarvinen    10 年前

    那么编译器为什么生成这样的类 Visitor_Name_Query_1 是抽象的吗?

    因为标准是这么说的。§14.5.2【temp.mem】/p4:

    成员函数模板的专用化不会重写 基类中的虚拟函数。[ 实例 :

    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
    };
    

    结束示例 ]

        2
  •  0
  •   jxh    10 年前

    看来你真的想要 Abstract_Visitor 以具有默认实现。如果移动 template 进入 摘要_访问者 ,你可以让每个 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); }
    };
    
        3
  •  0
  •   André Sassi    10 年前

    由于所有字段类型都有一个公共接口,如果可能,可以通过更改接口来简化问题:

    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";
      }
    };