template<typename T, int n> //带"非类型"的模板参数
class Array
{
private:
T* arr;
int size;
public:
//构造函数
Array() : arr(nullptr), size(n)
{
if (size > 0)
{
arr = new T[size];
}
}
//拷贝构造函数
Array(const Array& a) : arr(nullptr), size(a.size)
{
if (size > 0)
{
//先分配空间
arr = new T[size];
//再 拷贝
int i;
for (i = 0; i < size; i++)
{
(*this)[i] = a[i];
}
}
}
//析构函数
~Array()
{
if (arr)
{
delete[] arr;
}
}
// []下标运算符重载
T& operator[](const int& i)
{
if (i >= 0 && i < size)
{
return arr[i];
}
}
const T& operator[](const int& i) const
{
if (i >= 0 && i < size)
{
return arr[i];
}
}
// << 输出运算符重载
template<typename T, int n>
friend ostream& operator<<(ostream& o, const Array<T, n>& a);
};
// << 输出运算符重载
template<typename T, int n>
ostream& operator<<(ostream& o, const Array<T, n>& a)
{
int i;
for (i = 0; i < n; i++)
{
o << a[i] << " ";
}
o << endl;
return o;
}
在C++模板中,类模板内部声明友元函数时,如果直接使用模板参数`T`来声明友元函数,这会导致友元函数自身也成为模板函数的一个特例化版本,从而只能访问特定类型`T`的`Array`实例。然而,我们通常希望这个友元函数能与任何类型的`Array`实例配合使用,而不仅仅局限于定义`Array`类时指定的`T`类型。
因此,通过引入一个新的模板参数`U`:
template<typename U>
friend ostream& operator<<( ostream& o, const Array<U>& a );
这样声明的友元函数是一个独立的模板,它可以与任何类型的`Array`实例(不仅仅是原始模板参数`T`定义的类型)配合工作。这样的设计使得`operator<<`重载更加通用和灵活,能够处理`Array`的任何实例类型,只要类型`U`与所操作的`Array`实例类型匹配即可。
简而言之,直接使用`T`来声明友元函数:
friend ostream& operator<<( ostream& o, const Array<T>& a );
//会报错,编译器找不到对应的operator<<重载实现
这将限制友元函数只能与确切的`T`类型`Array`对象一起工作,而使用`U`允许该友元函数成为泛型,能够与任何类型的`Array`实例协同工作,提高了代码的复用性和灵活性。