[英]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 真有趣
g++
g++
给出 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
运算符,所以将其删除。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.