【问题标题】:Implementing overloads for >> and << operators in a template class在模板类中实现 >> 和 << 运算符的重载
【发布时间】:2017-11-26 08:21:04
【问题描述】:

我正在尝试编写用于在类定义之外重载运算符“>>”和“

1>Source.obj : error LNK2019: unresolved external symbol "class std::basic_istream<char,struct std::char_traits<char> > & __cdecl operator>>(class std::basic_istream<char,struct std::char_traits<char> > &,class MyClass<int> &)" (??5@YAAAV?$basic_istream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$MyClass@H@@@Z) referenced in function _main
1>Source.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class MyClass<int>)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@V?$MyClass@H@@@Z) referenced in function _main
1>Source.obj : error LNK2019: unresolved external symbol "class std::basic_istream<char,struct std::char_traits<char> > & __cdecl operator>>(class std::basic_istream<char,struct std::char_traits<char> > &,class MyClass<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > &)" (??5@YAAAV?$basic_istream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$MyClass@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@@Z) referenced in function _main
1>Source.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class MyClass<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@V?$MyClass@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@@Z) referenced in function _main

我一直在这条河上走来走去。奇怪的是,如果我在类定义中编写它们的定义,它就可以完美地工作。

#include <iostream>
#include <string>
using namespace std;

template <class MYTYPE>
class MyClass {
    MYTYPE *myVector;
    int dim;
    string name;
public:
    MyClass(int, string);
    MyClass() {};
    friend istream& operator>>(istream&, MyClass<MYTYPE>&);
    friend ostream& operator<<(ostream&, MyClass<MYTYPE>);
};

template <class MYTYPE>
MyClass<MYTYPE>::MyClass(int x, string y) {
    dim = x;
    name = y;
    myVector = new MYTYPE[dim];
}


template <class MYTYPE>
istream& operator>>(istream& X, MyClass<MYTYPE>& a){
    cout<<"Reading vector: "<<a.name<<endl;
    for(int indice = 0; indice < a.dim; indice++){
        cout<<a.name<<'['<<indice<<"]= ";
        X >> a.myVector[indice];
    }
    return X;
}

template <class MYTYPE>
ostream& operator<<(ostream& X, MyClass<MYTYPE> a){
    X<<"Vector: "<<a.name<<endl;
    for(int indice = 0; indice < a.dim; indice++)
        X<<a.myVector[indice]<<' ';
        X<<endl;
    return X;
}


int main() {
    MyClass<int> object(4, "Ints vector");
    MyClass<string> object2(5, "String vector");
    cin >> object;
    cin >> object2;
    cout << object;
    cout << object2;
    system("pause");
    return 0;
}

【问题讨论】:

  • 我在这里可能错了,但我认为您不需要包含 MyClass&lt;MYTYPE&gt; a 参数,因为您正在重载作用于该对象的运算符。只需将其称为this。但是,要使其正常工作,它需要成为课程的一部分,我认为这是另一个问题。
  • 应该是课程的一部分吗?
  • @EastonBornmeier 不,因为MyClass&lt;MYTYPE&gt; 是一个正确的论点
  • @alexeykuzmin0 这就是我尝试用我多年未使用过的语言解决问题的结果;)

标签: c++ templates operator-overloading


【解决方案1】:

在您的代码中,MyClass 中友元运算符的声明应如下所示:

template<typename T> friend istream& operator>>(istream&, MyClass<T>&);
template<typename T> friend ostream& operator<<(ostream&, MyClass<T>);

也就是说,它们应该有自己的模板参数。

基于问题中提供的MyClass有效定义如下:

template <class MYTYPE>
class MyClass { 
    MYTYPE *myVector;
    int dim;
    string name;
public:
    MyClass(int, string);
    MyClass() {}

    template<typename T>
    friend istream& operator>>(istream&, MyClass<T>&);

    template<typename T>
    friend ostream& operator<<(ostream&, MyClass<T>);
};

【讨论】:

  • 感谢您抽出宝贵的时间来写这篇文章!但是,它仍然拒绝为我解决问题。
  • @Marek It compiles and works just fine 这样做。由于您的代码的另一部分而出现警告,但这种方法至少解决了操作员的问题。
  • 真的!感谢您的解决方案!很抱歉误解了你的意思。没有注意到我那里有那个奇怪的缩进。
【解决方案2】:

提高编译器的警告级别会有所帮助。通过使用-Wallg++,我在链接器错误之前收到以下警告。

socc.cc:13:58: warning: friend declaration ‘std::istream& operator>>(std::istream&, MyClass<MYTYPE>&                    )’ declares a non-template function [-Wnon-template-friend]
     friend istream& operator>>(istream&, MyClass<MYTYPE>&);
                                                          ^
socc.cc:13:58: note: (if this is not what you intended, make sure the function template has already                     been declared and add <> after the function name here)
socc.cc:14:57: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, MyClass<MYTYPE>                     ’ declares a non-template function [-Wnon-template-friend]
     friend ostream& operator<<(ostream&, MyClass<MYTYPE>);

您需要为operator&gt;&gt;operator&lt;&lt; 函数使用函数模板。您可以在定义类之前声明它们:

// Forward the class template.
template <class MYTYPE> class MyClass;

// Declare the function templates.
template <class MYTYPE> 
std::istream& operator>>(std::istream&, MyClass<MYTYPE>&);

template <class MYTYPE> 
std::ostream& operator<<(st::ostream&, MyClass<MYTYPE>);

然后,您必须使用带有适当模板参数的friend 声明。

// This makes sure that operator>><int> is not a friend of MyClass<double>
// Only operator>><double> is a friend of MyClass<double>
friend std::istream& operator>><MYTYPE>(std::istream&, MyClass<MYTYPE>&);
friend std::ostream& operator<<<MYTYPE>(std::ostream&, MyClass<MYTYPE>);

这是为我构建的代码的更新版本。我还没有尝试运行它。

#include <iostream>
#include <string>
using namespace std;

template <class MYTYPE> class MyClass;

template <class MYTYPE> 
std::istream& operator>>(std::istream&, MyClass<MYTYPE>&);

template <class MYTYPE> 
std::ostream& operator<<(std::ostream&, MyClass<MYTYPE>);

template <class MYTYPE>
class MyClass {
    MYTYPE *myVector;
    int dim;
    string name;
public:
    MyClass(int, string);
    MyClass() {};

    friend std::istream& operator>><MYTYPE>(std::istream&, MyClass<MYTYPE>&);
    friend std::ostream& operator<<<MYTYPE>(std::ostream&, MyClass<MYTYPE>);
};

template <class MYTYPE>
MyClass<MYTYPE>::MyClass(int x, string y) {
    dim = x;
    name = y;
    myVector = new MYTYPE[dim];
}


template <class MYTYPE>
std::istream& operator>>(std::istream& X, MyClass<MYTYPE>& a){
    cout<<"Reading vector: "<<a.name<<endl;
    for(int indice = 0; indice < a.dim; indice++){
        cout<<a.name<<'['<<indice<<"]= ";
        X >> a.myVector[indice];
    }
    return X;
}

template <class MYTYPE>
std::ostream& operator<<(std::ostream& X, MyClass<MYTYPE> a){
    X<<"Vector: "<<a.name<<endl;
    for(int indice = 0; indice < a.dim; indice++)
        X<<a.myVector[indice]<<' ';
        X<<endl;
    return X;
}


int main() {
    MyClass<int> object(4, "Ints vector");
    MyClass<string> object2(5, "String vector");
    cin >> object;
    cin >> object2;
    cout << object;
    cout << object2;
    system("pause");
    return 0;
}

【讨论】:

  • 确实解决了问题。奇怪的是,我仍然得到这个:prntscr.com/fn1ixt 该程序运行良好,但仍然存在。
  • MyClass 中的友元函数声明不需要显式的MYTYPE 模板参数:friend std::istream&amp; operator&gt;&gt; &lt;&gt;(std::istream&amp;, MyClass&lt;MYTYPE&gt;&amp;);
  • @isanae,我不知道。感谢您的支持。
【解决方案3】:

这有点复杂。实际上,类模板有两种方式可以拥有函数朋友。

举个例子:

template <typename T>
void fun();

template <typename T>
class A
{
};

那你想要什么?

  1. 或者您是否希望 func&lt;X&gt;() 成为 A&lt;Y&gt; 的朋友以换取其他任何 Y
  2. 你想让fun&lt;X&gt;() 成为A&lt;X&gt; 的朋友,而不是A&lt;Y&gt; 的朋友吗?

也就是说,函数应该能够访问任何特化的私有成员还是只能访问相同类型的特化。

我的猜测是您需要选项 2。 诀窍是你必须使函数特化成为朋友,所以模板函数必须已经存在:你首先声明了模板函数,然后把它变成朋友。比如:

//first declare both function and class
template <typename T>
class A;
template <typename T>
void fun();

//Then define the class
template <typename T>
class A
{
    //A<T> is friend to fun<T>, the specializations must match.
    friend void fun<T>();
};

//And define the function
template <typename T>
void fun()
{
}

如果您想要的是选项 1,则不需要高级声明。只是:

template <typename T>
class A
{
    //A<T> is friend to fun<X>, T and X may be different
    template <class X>
    friend void fun();
};

也就是说,由于&lt;&lt;&gt;&gt;,您的代码编写起来有点棘手:

template <class MYTYPE>
class MyClass;

template <class MYTYPE>
istream& operator>>(istream& X, MyClass<MYTYPE>& a);

template <class MYTYPE>
ostream& operator<<(ostream&, MyClass<MYTYPE>);

template <class MYTYPE>
class MyClass {
    // ....
    friend istream& operator>> <MYTYPE>(istream&, MyClass<MYTYPE>&);
    friend ostream& operator<< <MYTYPE>(ostream&, MyClass<MYTYPE>);
};

【讨论】:

  • 非常感谢你也使用了一个抽象的例子!
猜你喜欢
  • 1970-01-01
  • 2013-03-21
  • 1970-01-01
  • 2016-10-15
  • 2016-04-21
  • 2013-03-24
  • 1970-01-01
  • 1970-01-01
  • 2016-06-21
相关资源
最近更新 更多