简体   繁体   English

动态数组模板类:ostream和操作员好友功能问题

[英]Dynamic Array Template Class: problem with ostream& operator friend function

Hi there fellow computer scientists, I'm having a lot of issues with my code, everything works except for the friend ostream& operator function. 嗨,计算机科学家们,我的代码遇到了很多问题,除好友ostream&运算符功能外,其他所有功能均正常运行。 I keep getting a compiler error when sending my class object to cout. 将类对象发送到cout时,我一直收到编译器错误。 I'm thinking a made an error while declaring the friend function or maybe within its declaration.Here is the code: 我在声明朋友功能或可能在其声明内时出错,代码如下:

By the way I know its traditional to use T for templates but I used my professors name, it sounds weird but using unconventional names in my code helps me remember programming concepts like templates and etc 顺便说一下,我知道使用T作为模板是传统的,但是我使用了教授的名字,这听起来很奇怪,但是在我的代码中使用非常规名称可以帮助我记住诸如模板等的编程概念

#include <iostream>
#include <cstdlib>

using namespace std;

template <class Chris>
class DynamicArray{


private:
    Chris *myArray;
     int capacity;
     int num_items;


public:
  DynamicArray();
  DynamicArray(int initialCapacity);
  void reSize(int newCapacity);
  void addElement(const Chris element);
  Chris& operator[](int index)const;
  friend std::ostream& operator << (std::ostream& outputStream, const 
  DynamicArray<Chris>& obj);
  virtual ~DynamicArray();


};


int main(){



DynamicArray<int> Array(20);

Array.addElement(20);
Array.addElement(12);
Array.addElement(13);
Array.addElement(45);
Array.addElement(78);



cout<<Array<<endl;












return 0;
}



template<class Chris>
ostream& operator<< (ostream& outputStream, const DynamicArray<Chris>& 
obj)
{

for(int index=0; index<obj.num_items; index++){

    if(index<(obj.num_items-1)){
    outputStream<<obj.myArray[index]<<",";
    }

    else{

        outputStream<<obj.myArray[index];
    }
   }


   return outputStream;
  }

 template<class Chris>
 DynamicArray<Chris>::DynamicArray():capacity(1),num_items(0)
 {

     myArray=new Chris[capacity];
 }

template <class Chris>
DynamicArray<Chris>::DynamicArray(int initialCapacity):num_items(0)
{

       if(initialCapacity>0){

    capacity=initialCapacity;
    myArray=new Chris[capacity];
}

    else{

       cout<<"ERROR, capacity cannot be negative or 0 " <<endl;
       exit(0);

      }

   }

 template <class Chris>
void DynamicArray<Chris>::reSize(int newCapacity)
 {

    if(newCapacity<=capacity){


        cout<<"ERROR, the new capacity must be greater than the current 
      capacity"<<endl;
        exit(1);
    }

    Chris *biggerArray = new Chris[newCapacity];

    for(int index=0; index<num_items; index++){

        biggerArray[index]=myArray[index];



    }

    delete [] myArray;
    capacity=newCapacity;
    myArray= new Chris[capacity];

       for(int index=0; index<num_items; index++){

        myArray[index]= biggerArray[index];



    }

    delete [] biggerArray;


   }

template <class Chris>
Chris& DynamicArray<Chris>::operator [](int index)const
{


if(index>=num_items){


    cout<<"ERROR,ARRAYINDEX OUT OF BOUNDS " <<endl;
    exit(0);
}

return myArray[index];



}





 template<class Chris>
 void DynamicArray<Chris>::addElement(const Chris element){

    if(num_items==capacity){


        reSize(capacity*2);
    }


    myArray[num_items]=element;
    num_items++;



}



template<class Chris>
DynamicArray<Chris>::~DynamicArray()
{


  delete [] myArray;
}

The compiler error is :undefined reference ,also it states that my friend ostream& function was not declared as a template. 编译器错误是:undefined reference,它还指出我的朋友ostream&函数未声明为模板。 I have to idea how to fix this 我要知道如何解决这个问题

To fix the issue above friend function must be declared at the top of the program before the class definition. 要解决以上问题,必须在程序的顶部,类定义之前声明friend函数。 The class that contains the friend functions should also be declared.I have edited my answer and also included the whole program. 包含友元函数的类也应该声明。我已经编辑了答案,还包括了整个程序。

#include <iostream>
#include <cstdlib>

using std::iostream;
using std::cout;
using std::endl;


template<typename Chris>
class DynamicArray; //must add this

template<typename Chris>
std::ostream& operator <<(std::ostream& outputStream, const 
DynamicArray<Chris>& 
    obj);// must add this as well



template <typename Chris>
 class DynamicArray{


    private:
    Chris *myArray;
    int capacity;
     int num_items;
     friend std::ostream& operator << <>(std::ostream& outputStream, const 
     DynamicArray& 
      obj);


    public:
    DynamicArray();
    DynamicArray(int initialCapacity);
    void reSize(int newCapacity);
    void addElement(const Chris element);
    Chris& operator[](int index)const;
    virtual ~DynamicArray();





















  };



  int main(){



   DynamicArray<int> Array(20);

   Array.addElement(20);
   Array.addElement(12);
   Array.addElement(13);
   Array.addElement(45);
   Array.addElement(78);



   cout<<Array<<endl;

    return 0;
   }

 template<typename Chris>
 DynamicArray<Chris>::DynamicArray():capacity(1),num_items(0)
   {

       myArray=new Chris[capacity];
    }

template <typename Chris>
DynamicArray<Chris>::DynamicArray(int initialCapacity):num_items(0)
    {

          if(initialCapacity>0){

           capacity=initialCapacity;
            myArray=new Chris[capacity];
      }

      else{

             cout<<"ERROR, capacity cannot be negative or 0 " <<endl;
              exit(0);

             }

            }

 template <typename Chris>
 void DynamicArray<Chris>::reSize(int newCapacity)
         {

                 if(newCapacity<=capacity){


                  cout<<"ERROR, the new capacity must be greater than the 
                 current capacity"<<endl;
                  exit(1);
                 }

                Chris *biggerArray = new Chris[newCapacity];

               for(int index=0; index<num_items; index++){

               biggerArray[index]=myArray[index];



              }

              delete [] myArray;
              capacity=newCapacity;
              myArray= new Chris[capacity];

               for(int index=0; index<num_items; index++){

               myArray[index]= biggerArray[index];



              }

              delete [] biggerArray;


             }

 template <typename Chris>
 Chris& DynamicArray<Chris>::operator [](int index)const
 {


    if(index>=num_items){


      cout<<"ERROR,ARRAYINDEX OUT OF BOUNDS " <<endl;
       exit(0);
   }

     return myArray[index];



   }



template<typename Chris>
void DynamicArray<Chris>::addElement(const Chris element){

    if(num_items==capacity){


        reSize(capacity*2);
    }


    myArray[num_items]=element;
    num_items++;



}

template<typename Chris>
std::ostream& operator<< (std::ostream& outputStream, const 
DynamicArray<Chris>&
obj)
{

   for(int index=0; index<obj.num_items; index++){

   if(index<(obj.num_items-1)){
    outputStream<<obj.myArray[index]<<",";
 }

     else{

         outputStream<<obj.myArray[index];
    }
   }


      return outputStream;
  }

template<typename Chris>
DynamicArray<Chris>::~DynamicArray()
{


   delete [] myArray;
}

Although OP seems to have solved her/his problem on its own, I became curious a bit. 尽管OP似乎已经单独解决了她/他的问题,但我还是有些好奇。

OP's problem seems to be to declare a free-standing friend operator<< in a class template. OP的问题似乎是在类模板中声明一个独立的friend operator<< OP's sample code is a bit hard to read, thus I made my own MCVE : OP的示例代码有点难以阅读,因此我制作了自己的MCVE

#include <iostream>
#include <exception>
#include <algorithm>

// template class for dynamic array
template <typename VALUE>
class VectorT {

  private:
    VALUE *_values;
    size_t _capacity;
    size_t _size;

  public:
    VectorT(): _values(nullptr), _capacity(0), _size(0) { }
    ~VectorT() { delete[] _values; }
    VectorT(const VectorT &vec); /// @todo
    VectorT& operator=(const VectorT &vec); /// @todo

    size_t capacity() const { return _capacity; }
    size_t size() const { return _size; }
    VALUE& operator[](size_t i) { return _values[i]; }
    const VALUE& operator[](size_t i) const { return _values[i]; }

    void push_back(const VALUE &value)
    {
      if (_size == _capacity) { // realloc necessary
        const size_t capacity = std::max(2 * _capacity, (size_t)1);
        VALUE *const values = new VALUE[capacity];
        if (!values) throw std::bad_array_new_length();
        std::move(_values, _values + _size, values);
        delete[] _values;
        _values = values; _capacity = capacity;
      }
      _values[_size++] = value;
    }

    friend std::ostream& operator<<(std::ostream&, const VectorT<VALUE>&);

};

// output stream operator for VectorT
template <typename VALUE>
std::ostream& operator<<(std::ostream &out, const VectorT<VALUE> &vec)
{
  const char *sep = "";
  for (size_t i = 0; i < vec._size; ++i) {
    out << sep << vec[i];
    sep = ", ";
  }
  return out;
}

// test
int main()
{
  VectorT<int> vec;
  // populate vec
  vec.push_back(20);
  vec.push_back(12);
  vec.push_back(13);
  vec.push_back(45);
  vec.push_back(78);
  // test output operator
  std::cout << vec << '\n';
  // done
  return 0;
}

Note: I changed the concept and names a bit as OP's DynamicArray does actually provide something similar like std::vector . 注意:我更改了概念并命名了一点,因为OP的DynamicArray确实提供了类似std::vector I found it reasonable to resemble it a bit closer. 我发现更接近它是合理的。

I tried to compile this with 我试图用

g++ --version ; g++ -std=c++11 -O2 -Wall -pedantic main.cpp && ./a.out

and got the following output: 并得到以下输出:

g++ (GCC) 8.1.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

main.cpp:38:73: warning: friend declaration 'std::ostream& operator<<(std::ostream&, const VectorT<VALUE>&)' declares a non-template function [-Wnon-template-friend]
     friend std::ostream& operator<<(std::ostream&, const VectorT<VALUE>&);
                                                                         ^
main.cpp:38:73: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) 
/tmp/ccvsl6kw.o: In function `main':
main.cpp:(.text.startup+0x9e): undefined reference to `operator<<(std::ostream&, VectorT<int> const&)'
collect2: error: ld returned 1 exit status

It's funny enough that 真有趣

  1. the ful answer is already given by g++ 完整的答案已经由g++给出
  2. and it consists actually of two activities: 它实际上包括两个活动:

make sure the function template has already been declared 确保功能模板已经被声明

and

add <> after the function name here 在函数名称后添加<>

Concerning the first part, I remembered a similar issue I once found in my answer to SO: Why would a struct need a friend function? 关于第一部分,我记得在我对SO的回答中曾经发现的一个类似问题:为什么结构需要朋友函数? .

The second part ( add <> after the function name here ) is something which raised my attention as I've never seen (nor used) it that way before. 第二部分( 在此处的函数名后面添加<> )引起了我的注意,因为我以前从未见过(也没有使用过)它。 So, I'd like to elaborate a bit. 所以,我想详细说明一下。

After having inserted the following forward declarations: 插入以下前向声明后:

// forward declaration of VectorT
template <typename VALUE>
class VectorT;

// prototyping of output stream operator
template <typename VALUE>
std::ostream& operator<<(std::ostream&, const VectorT<VALUE>&);

I tried to compile again and got again: 我试图再次编译并再次得到:

main.cpp:46:73: warning: friend declaration 'std::ostream& operator<<(std::ostream&, const VectorT<VALUE>&)' declares a non-template function [-Wnon-template-friend]
     friend std::ostream& operator<<(std::ostream&, const VectorT<VALUE>&);
                                                                         ^
main.cpp:46:73: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) 
/tmp/ccXLnkbV.o: In function `main':
main.cpp:(.text.startup+0x9e): undefined reference to `operator<<(std::ostream&, VectorT<int> const&)'
collect2: error: ld returned 1 exit status

exactly as before. 完全一样。 Oops! 糟糕!

My first reflex was to change the friend operator to a template friend operator : 我的第一反应是将friend operator更改为template friend operator

template <typename VALUE_>
friend std::ostream& operator<<(std::ostream&, const VectorT<VALUE_>&);

and this solved the issue: Live Demo on coliru . 这样就解决了问题: coliru上的Live Demo


However, this solution has a little flaw which might or might not be annoying: Any operator instance is friend to any VectorT template instance. 但是,此解决方案有一点缺陷,可能会或可能不会令人讨厌:任何运算符实例都是任何VectorT模板实例的朋友。 Actually, this should be constrained to only one operator instance – the one with the same VectorT template instance in signature. 实际上,这应该只限于一个运算符实例–签名中具有相同VectorT模板实例的VectorT This is what g++ actually suggested: 这是g++实际建议的内容:

friend std::ostream& operator<< <>(std::ostream&, const VectorT<VALUE>&);

Live Demo on coliru 在coliru上进行现场演示

I wonder why this isn't mentioned in theredfox24's answer – IMHO, this is the actually exciting part of OP's fix. 我想知道为什么在redfox24的答案中没有提到这一点-恕我直言,这实际上是OP修复中令人兴奋的部分。


Finally, I'd like to mention that (in this case) the “whole friend magic” is completely unnecessary. 最后,我想提一下(在这种情况下)“整个friend魔力”是完全没有必要的。 This is what raised my attention first – in the dozens of written output operators (for class templates), I never had any friend issues. 这就是首先引起我注意的原因-在数十种书面输出运算符(用于类模板)中,我从未遇到任何friend问题。 This can be easily prevented if the output operator uses public const members of the class exclusively (and I can hardly imagine why they shouldn't be available): 如果输出运算符仅使用class public const成员,则可以很容易地避免这种情况(而且我很难想象为什么不应该使用它们):

// output stream operator for VectorT
template <typename VALUE>
std::ostream& operator<<(std::ostream &out, const VectorT<VALUE> &vec)
{
  const char *sep = "";
  for (size_t i = 0; i < vec.size(); ++i) {
    out << sep << vec[i];
    sep = ", ";
  }
  return out;
}

(Forward declarations and friend operator removed because not needed anymore.) (因为不再需要转发声明和friend运算符,所以将其删除。)

Live Demo on coliru 在coliru上进行现场演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 operator &lt;&lt;(ostream&os,...)用于模板类 - operator<<(ostream& os, …) for template class operator&lt;&lt;(ostream&amp;, X) for class X 嵌套在 class 模板中 - operator<<(ostream&, X) for class X nested in a class template 朋友 std::ostream&amp; operator&lt;&lt; 声明不允许我访问类的私有成员 - friend std::ostream& operator<< declaration doesn't let me access the class' private members 对于这个朋友重载运算符 function 而不仅仅是 std::cout,std::ostream&amp; out 的目的是什么? - What is the purpose of std::ostream& out for this friend overloaded operator function and not just std::cout? “friend std::ostream&amp; operator&lt;&lt;(std::ostream&amp; out, LinkedList&amp; list)”是什么意思? - What does “friend std::ostream& operator<<(std::ostream& out, LinkedList& list)” mean? 朋友ostream&运营商&lt;&lt;无法访问私人会员 - Friend ostream& operator<< can't access private member 专业模板类的ostream好友功能 - ostream friend function of specialized template class ostream&运算符&lt;&lt;(ostream&(* pf)(ostream&)); - ostream& operator<< (ostream& (*pf)(ostream&)); “覆盖” ostream&运算符&lt; - “Overriding” ostream& operator << 未定义对 `operator&lt;&lt;(std::ostream&amp;, /* class 与非类型模板参数 */&amp;)' 的引用 - undefined reference to `operator<<(std::ostream&, /* class with non-type template parameters */&)'
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM