我无法理解运算符的行为<<在我班上:
头:
#ifndef VECTOR_H_
#define VECTOR_H_
#include <string>
#include <iostream>
template<class T>
class Vector {
static const int EXPANDER = 10;
T* array;
int next;
int length;
void expand();
void contract();
public:
Vector();
Vector(const Vector& v);
void add(const T e);
T get(int index) const;
bool removeByIndex(int index);
bool remove(T e);
int size() const;
T operator[](int i) const;
T& operator+=(const T& t);
T operator+(const T& s);
friend std::ostream& operator<< (std::ostream& os, const Vector<T>& obj);
friend std::istream& operator>> (std::istream& is, Vector<T>& obj);
std::string toString();
~Vector();
};
#endif /* VECTOR_H_ */
vector.cpp
#include "Vector.h"
#include <string>
#include <sstream>
template<class T>
Vector<T>::Vector() {
length = EXPANDER;
next = 0;
array = new T[EXPANDER];
}
template<class T>
Vector<T>::Vector(const Vector& v) {
length = v.next + 1 + EXPANDER;
next = v.next;
array = new T[length];
for (int i = 0; i <= v.next; i++) {
array[i] = v.array[i];
}
}
template<class T>
void Vector<T>::add(const T e) {
if (next >= length - 1)
expand();
array[next++] = e;
}
template<class T>
T Vector<T>::get(int index) const {
if (index > next)
return -1;
return array[index - 1];
}
template<class T>
bool Vector<T>::removeByIndex(int index) {
if (index > next)
return false;
for (int i = index; i < length; i++) {
array[i] = array[i + 1];
}
next--;
contract();
return true;
}
template<class T>
bool Vector<T>::remove(T e) {
int index = -1;
for (int i = 0; i < next; i++) {
if (array[i] == e) {
index = i;
break;
}
}
if (index == -1)
return false;
return removeByIndex(index);
}
template<class T>
int Vector<T>::size() const {
return next;
}
template<class T>
void Vector<T>::expand() {
length += EXPANDER;
T* temp = new T[length];
for (int i = 0; i < next; i++) {
temp[i] = array[i];
}
delete[] array;
array = temp;
}
template<class T>
void Vector<T>::contract() {
if (next + EXPANDER >= length)
return; // NO need to contract
length = next + EXPANDER + 1;
T* temp = new T[length];
for (int i = 0; i < next; i++) {
temp[i] = array[i];
}
delete[] array;
array = temp;
}
template<class T>
T Vector<T>::operator[](int i) const {
return get(i);
}
template<class T>
T& Vector<T>::operator+=(const T& t) {
for (int i = 0; i < t.size(); i++) {
add(t.get(i));
}
return *this;
}
template<class T>
T Vector<T>::operator+(const T& s) {
this += s;
return this;
}
template<class T>
std::ostream& operator<< (std::ostream& os, Vector<T>& obj) {
os << obj.toString();
return os;
}
template<class T>
std::istream& operator>> (std::istream& is, Vector<T>& obj) {
int size;
T temp;
is >> size;
for (int i = 0; i < size; i++) {
is >> temp;
add(temp);
}
return is;
}
template<class T>
std::string Vector<T>::toString() {
using namespace std;
ostringstream sb;
sb << "Elements(" << size() << "): [";
for (int i = 0; i < next; i++) {
sb << array[i] << ", ";
}
string r;
r = sb.str();
r = r.substr(0, r.size() - 2) + string("]");
return r;
}
template<class T>
Vector<T>::~Vector() {}
我用main.cpp运行此代码
#include "Vector.h"
#include "Vector.cpp"
#include <string>
#include <iostream>
using namespace std;
int main() {
Vector<int> v;
v.add(1);
v.add(2);
cout << v << endl;
}
魔法在标题中的operator<<
声明中。如果我删除CONST修饰符,编译器说:Undefined reference to operator<<
,但使用const它可以工作。有趣的是,在我的实现中,在cpp中,我没有CONST。
顺便说一句,如何解决运营商使用warning: friend declaration declares a non-template function
的警告?
答案 0 :(得分:7)
你应该学会如何将其归结为Short, Self-Contained, Compilable Example又名最小工作范例。
这是一个证明问题的SSCCE:
#include <iostream>
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
T get() const { return m; }
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T>& v)
{
// accessing a private member leads to a compiler error here:
return o << "[function template]" << /*v.m*/ v.get();
}
// remove this function to get the same behaviour as in the OP
std::ostream& operator<<(std::ostream& o, Vector<int> const& v)
{
return o << "function" << v.m;
}
int main()
{
Vector<int> v(42);
std::cout << v;
}
请注意,它只有大约30行,并且可以放在一个没有滚动条的屏幕上。
现在,问题是基于类模板中的朋友声明:
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
这会在周围的范围中查找名为operator<<
的函数,以与此已存在的函数成为一个伙伴。但它没有找到任何匹配那些参数类型。因此,它在周围(=全局)命名空间中声明一个新函数。此功能如下所示:
std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
(在全局命名空间中) 注意:它只能通过Argument-Dependent Lookup找到,如果它只通过friend-declaration声明。
现在,您稍后声明了一个同名的功能模板。但是,当您在之前在类模板中编写好友声明时,编译器无法知道您打算与此函数模板成为联系人。所以那两个,朋友功能和功能模板是不相关的。
现在发生的是通常的重载分辨率。如果不添加const,则首选函数模板,因为您使用非const参数调用它:
Vector<int> v;
v.add(1);
v.add(2);
cout << v << endl; // v is not const
对于类型为Vector<int>
的此参数,与函数模板(特化)的Vector<int>&
的绑定优先于对友元函数的Vector<int> const&
的绑定。因此,选择了函数模板,它具有定义(函数体),并且所有内容都编译,链接和工作。请注意,函数模板不是友好的,但由于您不使用任何私有成员,因此不会引发错误。
将const
添加到函数模板后,函数模板不再是参数的更好匹配。由于我们有一个具有相同重载“rank”的函数和函数模板,因此非模板是首选。问题是,调用了友元函数,它没有定义=&gt;发生链接器错误。
最简单的解决方案是在类定义中定义友元函数:
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
};
使用前向声明的解决方案:
template<class T>
class Vector;
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<< <T>(std::ostream& o, Vector<T> const& v);
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
现在,编译器可以找到前向声明的函数模板并与现有函数(函数模板的特化)保持联系,而不是声明一个新函数。
与整个功能模板交朋友的解决方案:
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
template<class U>
friend std::ostream& operator<<(std::ostream& o, Vector<U> const& v);
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
在这个解决方案中,friend-declaration声明了一个函数模板,并且在命名空间范围内的后面声明遵循类'definition redeclares 这个函数模板。