如何在C++中用模板化函数实现父类?
我有一个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
任何想法可能是错误的? 基本上我想创建接口类与模板函数哪些子类将指定和实现。
任何帮助,将不胜感激。谢谢。
首先让我们看看错误是什么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();
}
有三个原因,因为你预期,这将不起作用:
- 第2个参数是按值在基类成员函数的声明(JSON ::对象)通过,但你通过在派生类中引用(json :: Object &)。由于它们具有不同的签名,因此编译器将此视为基类成员函数的“重载”版本。
- 如果你修正了第一个错误,并且在基类中声明第二个参数是通过引用(json :: Object &),那么签名将匹配,但是链接器仍然会抱怨,因为你试图调用基类成员函数,尚未定义。你所做的是“覆盖”基类
Parse
成员函数,所以如果你使用指向派生类的指针HTMLParser
来调用你的派生类成员函数将被调用。如果您尝试使用指向基类IParser
的指针调用Parse
成员函数,那么编译器会生成对该函数的调用(它们是不同的!),但您尚未定义它。那么,当你使用指向基类IParser
的指针调用派生类HTMLParser::Parse
的成员函数时,为了使编译器调用Parse
的成员函数,你该怎么做?为了做到这一点,你需要了解polymorphism and virtual inheritance。好的,你说,我将使IParser
基类的Parse
成员函数为纯虚拟,并强制每个派生类提供一个定义。那时你会遇到第三个问题。 - 无法在成员函数模板上指定'虚拟'。原因是模板在编译时被解析,而虚拟函数是基于与实例(指针)关联的类型的called dynamically at runtime。
一个办法来解决的尝试同时使用泛型编程(模板)这个问题和面向对象编程(继承)是使用一种叫做类型擦除模式,在某些情况下工作......你可以阅读更多在On the Tension Between Object-Oriented and Generic Programming in C++ and What Type Erasure Can Do About It
感谢您的详尽回复,我纠正了前面提到的第二个问题,第三个问题出现了,所以我会按照您的建议查看“类型擦除”。谢谢! – 2014-11-06 20:36:28
正如你可以看到@ Jarod42对他的评论是正确的,我们只是在显然之前解决了一些事情。类型擦除对您的问题来说可能太大了,您必须决定是否需要这种灵活性。 – amdn 2014-11-06 20:53:31
让全班模板:
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);
};
我想避免创建**模板类**,因为在主函数中我只想创建一个类型为'IParser'的变量,并基于子类的输入创建对象,例如: 'IParser * parser = new HTMLParser )'或'IParser * parser = new XMLParser()'等等。 – 2014-11-06 16:34:51
模板方法不能是虚拟的。 – Jarod42 2014-11-06 16:24:06
所以我不能定义一个具有不同的第一个参数的方法,孩子们将使用特定类型来实现吗? – 2014-11-06 16:28:37