动态数组模板 Class:ostream& 运算符友元函数有问题
Dynamic Array Template Class: problem with ostream& operator friend function
各位计算机科学家大家好,
我的代码有很多问题,除了 friend ostream& 运算符函数外,一切正常。将我的 class 对象发送到 cout 时,我不断收到编译器错误。我在想在声明 friend 函数时出错,或者在它的 declaration.Here 中可能是代码:
顺便说一句,我知道使用 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;
}
编译器错误是:未定义的引用
,它还指出我的朋友 ostream& 函数未声明为模板。
我得想办法解决这个问题
修复上述友元函数必须在程序顶部声明的问题
在 class 定义之前。包含好友函数的class也应该是declared.I编辑了我的答案,也包含了整个程序。
#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好像自己解决了her/his问题,但我还是有点好奇。
OP 的问题似乎是在 class 模板中声明一个独立的 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
这很有趣
- ful 答案已由
g++
给出
- 它实际上包含两个活动:
make sure the function template has already been declared
and
add <> after the function name here
关于第一部分,我想起了我曾经在的回答中发现的类似问题。
第二部分(在此处的函数名称后添加 <>)引起了我的注意,因为我以前从未见过(也没有使用过)这种方式。所以,我想详细说明一下。
插入以下前向声明后:
// 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>&);
我想知道为什么 中没有提到这一点 – 恕我直言,这是 OP 修复中真正令人兴奋的部分。
最后,我想提一下(在这种情况下)“整个 friend
魔术”是完全没有必要的。这是首先引起我注意的——在几十个书面输出操作符(对于 class 模板)中,我从来没有遇到任何 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
运算符,因为不再需要了。)
各位计算机科学家大家好, 我的代码有很多问题,除了 friend ostream& 运算符函数外,一切正常。将我的 class 对象发送到 cout 时,我不断收到编译器错误。我在想在声明 friend 函数时出错,或者在它的 declaration.Here 中可能是代码:
顺便说一句,我知道使用 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;
}
编译器错误是:未定义的引用 ,它还指出我的朋友 ostream& 函数未声明为模板。 我得想办法解决这个问题
修复上述友元函数必须在程序顶部声明的问题 在 class 定义之前。包含好友函数的class也应该是declared.I编辑了我的答案,也包含了整个程序。
#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好像自己解决了her/his问题,但我还是有点好奇。
OP 的问题似乎是在 class 模板中声明一个独立的 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
这很有趣
- ful 答案已由
g++
给出
- 它实际上包含两个活动:
make sure the function template has already been declared
and
add <> after the function name here
关于第一部分,我想起了我曾经在
第二部分(在此处的函数名称后添加 <>)引起了我的注意,因为我以前从未见过(也没有使用过)这种方式。所以,我想详细说明一下。
插入以下前向声明后:
// 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>&);
我想知道为什么
最后,我想提一下(在这种情况下)“整个 friend
魔术”是完全没有必要的。这是首先引起我注意的——在几十个书面输出操作符(对于 class 模板)中,我从来没有遇到任何 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
运算符,因为不再需要了。)