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

时间:2019-01-02 15:47:33

标签: c++ templates ostream

您好,计算机科学家们, 我的代码有很多问题,除了朋友的ostream&运算符功能之外,其他所有功能都可以正常工作。将类对象发送到cout时,我一直收到编译器错误。我在声明朋友功能或声明其范围内时认为是错误的。代码如下:

通过我知道使用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;
}

编译器错误是:undefined reference ,它还指出我的朋友ostream&函数未声明为模板。 我必须想办法解决这个问题

2 个答案:

答案 0 :(得分:1)

要解决上述问题,必须在程序顶部声明朋友功能 在类定义之前。包含朋友功能的类也应该声明。我已经编辑了答案,还包含了整个程序。

#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;
}

答案 1 :(得分:1)

尽管OP似乎已经单独解决了她/他的问题,但我有点好奇。

OP的问题似乎是在类模板中声明一个独立的friend operator<<。 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;
}

注意:我更改了概念并命名了一点,因为OP的DynamicArray实际上提供了类似std::vector的功能。我觉得更接近它是合理的。

我试图用

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

并获得以下输出:

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

这很有趣

  1. 的答案已经由g++
  2. 给出
  3. 它实际上包括两个活动:
  

确保已声明功能模板

     

     在函数名称后

添加<>

关于第一部分,我还记得我在对SO: Why would a struct need a friend function?的回答中发现的一个类似问题。

第二部分(在此处的函数名称后的 add <> )引起了我的注意,因为我以前从未见过(也没有使用过)。所以,我想详细说明一下。

在插入以下前向声明之后:

// 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>&);

我试图再次编译并再次得到:

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

与以前完全相同。糟糕!

我的第一个反应是将friend operator更改为template friend operator

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

这解决了问题: Live Demo on coliru


但是,此解决方案有一个小缺陷,可能会或可能不会令人讨厌:任何运算符实例都是任何VectorT模板实例的朋友。实际上,这应仅限于一个运算符实例–签名中具有相同VectorT模板实例的那个运算符实例。这是g++的实际建议:

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

Live Demo on coliru

我想知道为什么theredfox24's answer中没有提到这一点–恕我直言,这实际上是OP修复中令人兴奋的部分。


最后,我想提一下(在这种情况下)“ friend的整个魔术”是完全没有必要的。这首先引起了我的注意-在数十个书面输出运算符(用于类模板)中,我从未遇到任何friend问题。如果输出运算符仅使用public的{​​{1}} const个成员,这很容易避免(而且我很难想象为什么不应该使用它们):

class

(由于不再需要转发声明和// 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; } 运算符,因此将其删除。)

Live Demo on coliru