【问题标题】:Overloading operator<< template classes [duplicate]重载运算符<<模板类[重复]
【发布时间】:2021-09-19 23:42:29
【问题描述】:

我正在使用 Microsoft Visual Studio 作为源代码编辑器,当我尝试编译以下代码时出现链接器错误:

LNK2019 未解析的外部符号 "class std::basic_ostream > & __cdecl operator > &,类 X &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$X@H@@@Z) 在函数 _main Zadatak7 中引用.19.04.2021 C:\Users\AT95\Desktop\Zadatak7.19.04.2021\Zadatak7.19.04.2021\main.obj 1

我必须怎样做才能使这个程序正常工作?

我想让你看一下重载operator&lt;&lt;的定义,因为 该方法导致错误。

#include <iostream>

template <class T>
class X
{

private:

    int index, capacity;

    T* collection{};
        
public:

    X(const int nmb, const T* array)
    {
        index = 0;

        capacity = nmb;

        collection = new(T[nmb]);

        for (int i = 0; i < nmb; i++)
            collection[index++] = array[i];
    }

    X(const X& other)
    {
        index = other.index;
        capacity = other.capacity;

        collection = new(T[other.capacity]);

        if(other.index < other.capacity)
            for (int i = 0; i < other.index; i++)
                collection[i] = other.collection[i];
    }

    ~X() { delete[] collection; }

    friend std::ostream& operator<<(std::ostream&, X<T>&);

};
        
template <class T>
std::ostream& operator<<(std::ostream& out, X<T>& other)
{
    for (int i = 0; i < other.index; i++)
        out << i + 1 << ". " << other.collection[i];

    return out;
}

int main()
{
    int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, n = sizeof(array)/sizeof(int);

    X<int> x(n, array), b(x);

    std::cout << x;

    return 0;
}

【问题讨论】:

  • 收集一系列警告 - 实时 - godbolt.org/z/3n841MbMj - 以我的方式解决它们。
  • 非常有用的网站,我会尽我所能去看看。朋友,谢谢。非常感谢您的帮助。
  • @AndrejTrozic 无论是否使用该站点,提示都是打开编译器警告并阅读它们。他们会告诉你你的代码在哪里看起来有问题。
  • 该站点也很有帮助,因为很高兴了解其他编译器对您的代码的看法。不同的编译器给出不同的诊断,一个编译器可能会发现其他人没有发现的问题或更好地解释问题。它们会生成不同的输出并对some coding mistakes 有不同的解释,并且它们输出中的差异有助于发现隐秘的错误。

标签: c++ operator-overloading


【解决方案1】:

你的朋友声明是错误的。

    friend std::ostream& operator<<(std::ostream&, X<T>&);

这是一个非模板operator&lt;&lt; 的朋友声明。

应该是这样的:

    template<typename Z>
    friend std::ostream& operator<<(std::ostream&, X<Z>&);

但是有一个更好的方法来声明它。将函数体移动到类中,就不需要声明模板部分了。

template <class T>
class X
{

    // STUFF AS BEFORE


    // Friend class definition.
    friend std::ostream& operator<<(std::ostream& out, X& other)
    {
        for (int i = 0; i < other.index; i++)
            out << i + 1 << ". " << other.collection[i];

        return out;
    }
}

次要说明。在输出运算符中,被输出的对象通常被声明为 const(因为输出它不应该修改它)。

friend std::ostream& operator<<(std::ostream& out, X const& other)
                                                        ^^^^^

【讨论】:

  • 你也可以在课堂上使用friend std::ostream&amp; operator&lt;&lt;(std::ostream&amp; out, X&amp; other) { ... }
  • @RSahu 已修复。年纪大了就生锈了。
  • 老年有它的缺点:) :)
【解决方案2】:

你需要在friend函数的开头写上template关键字,像这样:

#include <iostream>

template <class T>
class X
{

private:

    int index, capacity;

    T* collection{};

public:

    X(const int nmb, const T* array)
    {
        index = 0;

        capacity = nmb;

        collection = new(T[nmb]);

        for (int i = 0; i < nmb; i++)
            collection[index++] = array[i];
    }

    X(const X& other)
    {
        index = other.index;
        capacity = other.capacity;

        collection = new(T[other.capacity]);

        if(other.index < other.capacity)
            for (int i = 0; i < other.index; i++)
                collection[i] = other.collection[i];
    }

    ~X() { delete[] collection; }

    template<class U> friend std::ostream& operator<<(std::ostream&, X<U>&);

};

template <class T>
std::ostream& operator<<(std::ostream& out, X<T>& other)
{
    for (int i = 0; i < other.index; i++)
        out << i + 1 << ". " << other.collection[i];

    return out;
}

int main()
{
    int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, n = sizeof(array)/sizeof(int);

    X<int> x(n, array), b(x);

    std::cout << x;

    return 0;
}

【讨论】:

  • 是的,就是这样。一个班级的朋友是他自己的。谢谢楼主!
  • 没关系!
  • 当您将template 添加到朋友声明中时,您将operator&lt;&lt;(std::ostream&amp;, X&lt;U&gt;&amp;) 成为所有Us 的朋友。形式上,这种方法是有效的,但从架构的角度来看是错误的——友谊范围应该尽可能地窄。更好的解决方案是让编译器知道operator&lt;&lt; 是一个具有正确前向声明的模板,如here 所述。
猜你喜欢
  • 2012-11-14
  • 2016-02-03
  • 2013-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-21
  • 2015-09-15
相关资源
最近更新 更多