繁体   English   中英

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

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

嗨,计算机科学家们,我的代码遇到了很多问题,除好友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&函数未声明为模板。 我要知道如何解决这个问题

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

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

尽管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. 它实际上包括两个活动:

确保功能模板已经被声明

在函数名称后添加<>

关于第一部分,我记得在我对SO的回答中曾经发现的一个类似问题:为什么结构需要朋友函数?

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

插入以下前向声明后:

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

这样就解决了问题: coliru上的Live Demo


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

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

在coliru上进行现场演示

我想知道为什么在redfox24的答案中没有提到这一点-恕我直言,这实际上是OP修复中令人兴奋的部分。


最后,我想提一下(在这种情况下)“整个friend魔力”是完全没有必要的。 这就是首先引起我注意的原因-在数十种书面输出运算符(用于类模板)中,我从未遇到任何friend问题。 如果输出运算符仅使用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;
}

(因为不再需要转发声明和friend运算符,所以将其删除。)

在coliru上进行现场演示

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM