2014-11-06 41 views
1

我有一个folllowing问题:如何在C++中用模板化函数实现父类?

我想要实现的类结构如下:在HTMLParser.h

#ifndef HTMLPARSER_H 
#define HTMLPARSER_H 

#include <iostream> 

#include "IParser.h" 

class HTMLParser : public IParser 
{ 
public: 
    HTMLParser(); 
    ~HTMLParser(); 

    json::Object Parse(std::string const&, json::Object&); 
}; 

#endif 
    • 家长在IParser.h

      #ifndef IPARSER_H 
      #define IPARSER_H 
      
      #include "json.h" 
      
      class IParser 
      { 
      public: 
          template <typename T> 
          json::Object Parse(const T&, json::Object); 
      }; 
      
      #endif // IPARSER_H 
      
    • 儿童孩子HTMLParser.cpp

      #include "HTMLParser.h" 
      
      HTMLParser::HTMLParser() 
      { 
          std::cout << "constructed" << std::endl; 
      } 
      
      HTMLParser::~HTMLParser() 
      { 
          std::cout << "destructed" << std::endl; 
      } 
      
      json::Object HTMLParser::Parse(std::string const& data, json::Object& object) 
      { 
          // do something 
          return json::Object(); 
      } 
      

    但是,当我想建立它,它抛出我这个错误:

    error LNK2019: unresolved external symbol "public: class json::Object __thiscall 
    IParser::Parse<class std::basic_string<char,struct std::char_traits<char>,class 
    std::allocator<char> > >(class std::basic_string<char,struct std::char_traits<char>,class 
    std::allocator<char> > const &,class json::Object)" ([email protected][email protected]? 
    [email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@[email protected]@[email protected]@@[email protected]? 
    [email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@Z) referenced in function _main 
    

    任何想法可能是错误的? 基本上我想创建接口类与模板函数哪些子类将指定和实现。

    任何帮助,将不胜感激。谢谢。

  • +0

    模板方法不能是虚拟的。 – Jarod42 2014-11-06 16:24:06

    +0

    所以我不能定义一个具有不同的第一个参数的方法,孩子们将使用特定类型来实现吗? – 2014-11-06 16:28:37

    回答

    1

    首先让我们看看错误是什么tr你要告诉你,不是非常雄辩。该错误是从连接

    error LNK2019: unresolved external symbol 
    

    所以编译器是确定你的代码来了,它只是它创建了一个符号,链接器没有找到相关性。符号是

    "public: class json::Object __thiscall IParser::Parse< class std::basic_string < char,struct std::char_traits < char >,class std::allocator < char > > >(class std::basic_string < char,struct std::char_traits < char >,class std::allocator < char > > const &,class json::Object)" blah blah mangled signature ... referenced in function _main

    ,这不是很可读,让使其更具可读性通过使这种替代

    using string = class std::basic_string < char,struct std::char_traits < char >,class std::allocator < char > >

    现在的错误是

    "public: class json::Object __thiscall IParser::Parse< string >(class string const &, class json::Object)"

    它说的是,在函数_main您正在调用Parse<string>函数,该函数是具有两个参数的类Iparser的成员,这两个参数是一个字符串的常量引用和一个json :: Object按价值。

    但是,等等,你说我确实在派生类中提供了一个定义!

    json::Object HTMLParser::Parse(std::string const& data, json::Object& object) 
    { 
        // do something 
        return json::Object(); 
    } 
    

    有三个原因,因为你预期,这将不起作用:

    1. 第2个参数是按值在基类成员函数的声明(JSON ::对象)通过,但你通过在派生类中引用(json :: Object &)。由于它们具有不同的签名,因此编译器将此视为基类成员函数的“重载”版本。
    2. 如果你修正了第一个错误,并且在基类中声明第二个参数是通过引用(json :: Object &),那么签名将匹配,但是链接器仍然会抱怨,因为你试图调用基类成员函数,尚未定义。你所做的是“覆盖”基类Parse成员函数,所以如果你使用指向派生类的指针HTMLParser来调用你的派生类成员函数将被调用。如果您尝试使用指向基类IParser的指针调用Parse成员函数,那么编译器会生成对该函数的调用(它们是不同的!),但您尚未定义它。那么,当你使用指向基类IParser的指针调用派生类HTMLParser::Parse的成员函数时,为了使编译器调用Parse的成员函数,你该怎么做?为了做到这一点,你需要了解polymorphism and virtual inheritance。好的,你说,我将使IParser基类的Parse成员函数为纯虚拟,并强制每个派生类提供一个定义。那时你会遇到第三个问题。
    3. 无法在成员函数模板上指定'虚拟'。原因是模板在编译时被解析,而虚拟函数是基于与实例(指针)关联的类型的called dynamically at runtime

    一个办法来解决的尝试同时使用泛型编程(模板)这个问题和面向对象编程(继承)是使用一种叫做类型擦除模式,在某些情况下工作......你可以阅读更多在On the Tension Between Object-Oriented and Generic Programming in C++ and What Type Erasure Can Do About It

    +0

    感谢您的详尽回复,我纠正了前面提到的第二个问题,第三个问题出现了,所以我会按照您的建议查看“类型擦除”。谢谢! – 2014-11-06 20:36:28

    +0

    正如你可以看到@ Jarod42对他的评论是正确的,我们只是在显然之前解决了一些事情。类型擦除对您的问题来说可能太大了,您必须决定是否需要这种灵活性。 – amdn 2014-11-06 20:53:31

    0

    让全班模板:

    template <typename T> 
    class IParser 
    { 
    public: 
        json::Object Parse(const T&, json::Object); 
    }; 
    

    然后你的子类可以从模板类继承:

    class HTMLParser : public IParser<std::string> 
    

    需要注意的是,从不同的模板版本继承的类将没有一个共同的基类,所以你可能想要:

    class IParserBase 
    { 
        //... 
    }; 
    
    template <typename T> 
    class IParser : public IParserBase 
    { 
    public: 
        json::Object Parse(const T&, json::Object); 
    }; 
    
    +0

    我想避免创建**模板类**,因为在主函数中我只想创建一个类型为'IParser'的变量,并基于子类的输入创建对象,例如: 'IParser * parser = new HTMLParser )'或'IParser * parser = new XMLParser()'等等。 – 2014-11-06 16:34:51

    相关问题