C++ 中的朋友和模板
friend and template in C++
我的 C++ 代码示例中有一个大问题。 'friend' 和 'template'.
有问题
错误信息:
Matrix.h:26:79: 警告:
friend declaration 'std::ostream&
matrixClass::operator<<(std::ostream&, const matrixClass::Matrix&)'
declares a non-template function [-Wnon-template-friend]
friend std::ostream &operator<<(std::ostream&, const Matrix &matrix);
Matrix.h:26:79: 注:
(if this is not what you intended, make sure the function template
has already been declared and add <> after the function name here)
Matrix.h:28:77:警告:
friend declaration 'matrixClass::Matrix<T>*
matrixClass::operator*(const matrixClass::Matrix&, const
matrixClass::Matrix&)' declares a non-template function
[-Wnon-template-friend]
friend Matrix* operator*(const Matrix &m1, const Matrix &m2);
Matrix.cpp:1:0:
C:\Users\Peter\CLionProjects\PK\untitled76\Matrix.h:26:79: warning:
friend declaration 'std::ostream&
matrixClass::operator<<(std::ostream&, const matrixClass::Matrix&)'
declares a non-template function [-Wnon-template-friend]
friend std::ostream &operator<<(std::ostream&, const Matrix &matrix);
Matrix.h:26:79: 注:
(if this is not what you intended, make sure the function template
has already been declared and add <> after the function name here)
Matrix.h:28:77:警告:
friend declaration 'matrixClass::Matrix<T>*
matrixClass::operator*(const matrixClass::Matrix&, const
matrixClass::Matrix&)' declares a non-template function
[-Wnon-template-friend]
friend Matrix* operator*(const Matrix &m1, const Matrix &m2);
CMakeFiles\untitled76.dir/objects.a(main.cpp.obj): 在函数`main'中:
main.cpp:8: 未定义引用
main.cpp:8: 对 matrixClass::Matrix<int>::Matrix(int)'<br>
main.cpp:10: undefined reference to
matrixClass::Matrix::set(int, int, int)'
的未定义引用
main.cpp:11: 对 matrixClass::Matrix<int>::set(int, int, int)'<br>
main.cpp:12: undefined reference to
matrixClass::Matrix::set(int, int, int)'
的未定义引用
main.cpp:13: 对 matrixClass::Matrix<int>::set(int, int, int)'<br>
main.cpp:15: undefined reference to
matrixClass::operator<<(std::ostream&, matrixClass::Matrix const&)'
的未定义引用
main.cpp:15: 对 matrixClass::operator<<(std::ostream&, matrixClass::Matrix<int> const&)'<br>
main.cpp:8: undefined reference to
matrixClass::Matrix::~Matrix()'
的未定义引用
main.cpp:8: 未定义引用`matrixClass::Matrix::~Matrix()'
代码:
Matrix.h
#ifndef MATRIX_H_
#define MATRIX_H_
#include <iostream>
namespace matrixClass {
template<class T>
class Matrix {
private:
int dimension;
T **m;
public:
Matrix(int d);
Matrix(const Matrix &original);
~Matrix();
void set(int x, int y, T value);
T get(int x, int y) const;
int getDimension() const;
friend std::ostream &operator<<(std::ostream&, const Matrix<T> &matrix);
friend Matrix<T>* operator*(const Matrix<T> &m1, const Matrix<T> &m2);
};
}
#endif
Matrix.cpp
#include "Matrix.h"
using namespace matrixClass;
template<class T>
Matrix<T>::Matrix(int d)
: dimension{d}, m{new T *[d]} {
//m = new T*[d];
for (int i = 0; i < d; i++) {
m[i] = new T[d];
}
}
// COPY-CONSTRUCTOR
template<class T>
Matrix<T>::Matrix(const Matrix &original)
: dimension{original.dimension},
m{new T *[original.dimension]} {
for (int i = 0; i < dimension; i++) {
*(m + i) = *(original.m + i);
}
}
// DESTRUCTOR
template<class T>
Matrix<T>::~Matrix() {
for (int i = 0; i < dimension; i++) {
delete[] m[i];
}
delete[] m;
}
template<class T>
void Matrix<T>::set(int x, int y, T value) {
m[x][y] = value;
}
template<class T>
T Matrix<T>::get(int x, int y) const {
return m[x][y];
}
template<class T>
int Matrix<T>::getDimension() const {
return dimension;
}
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix) {
int dimension = matrix.getDimension();
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
output << matrix.get(x, y) << " ";
}
return output;
}
}
template<class T>
Matrix<T>* operator*(const Matrix<T>& m1, const Matrix<T>& m2) {
int dimension = m1.getDimension();
Matrix<T>* m = new Matrix<T>(dimension);
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
T value = 0;
for(int i = 0; i < dimension; i++) {
value += m1.get(x, i) * m2.get(i, y);
}
m->set(x, y, value);
}
}
return m;
}
main.cpp
#include <iostream>
#include "Matrix.h"
using namespace matrixClass;
using namespace std;
int main() {
Matrix<int> m(2);
m.set(0, 0, 1);
m.set(0, 1, 2);
m.set(1, 0, 3);
m.set(1, 1, 4);
cout << m << "*" << endl << m << "=" << endl;
return 0;
}
在friend
声明中operator<<
引用了一个非模板函数,而它的定义说它是一个模板函数;他们不匹配。
您可以在 friend
声明中内联定义它(作为非模板函数):
template<class T>
class Matrix {
... ...
friend std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix) {
int dimension = matrix.getDimension();
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
output << matrix.get(x, y) << " ";
}
return output;
}
}
... ...
};
或者friend
声明引用函数模板:
// class declaration
template<class T>
class Matrix;
// function declaration
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix);
// class definition
template<class T>
class Matrix {
... ...
friend std::ostream& operator<< <T>(std::ostream& output, const Matrix<T>& matrix);
... ...
};
// function definition
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix) {
int dimension = matrix.getDimension();
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
output << matrix.get(x, y) << " ";
}
return output;
}
}
关于未定义引用错误,参见Why can templates only be implemented in the header file?
此答案解决了您的非成员 operator<<()
和 operator*()
使用好友模板的问题,这与将函数模板的实例设为好友略有不同(第二个解决方案由@宋元尧)。不同之处在于,使用友元模板时,模板函数的所有实例都是 class Matrix<>
的友元。在这种情况下,我认为没有任何实际差异,但在其他情况下,可能会有。因此,我想无论如何我都会展示它。
我是这样想的。这两个运算符都是非成员函数,这意味着它们独立于 class Matrix<>
,因此请独立考虑它们的原型:
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix);
template<class T>
Matrix<T>* operator*(const Matrix<T>& m1, const Matrix<T>& m2);
现在,将 T
替换为 U
,因为要使它们的所有实例成为 Matrix<>
的朋友,它们的原型需要包含在 class 定义中 Matrix<>
这也是一个模板,它已经使用 T
作为它的模板参数。
template<class U>
std::ostream& operator<<(std::ostream& output, const Matrix<U>& matrix);
template<class U>
Matrix<U>* operator*(const Matrix<U>& m1, const Matrix<U>& m2);
现在,您可以让他们成为 Matrix<>
的朋友。您只需要适当的语法:
template<class T>
class Matrix
{
...
template<class U>
friend std::ostream &operator<<(std::ostream&, const Matrix<U> &matrix);
template<class U>
friend Matrix<U>* operator*(const Matrix<U> &m1, const Matrix<U> &m2);
};
最后,它们都需要在 matrixClass
namespace
内,并且它们的声明和定义需要以正确的顺序排列,以便每个人都知道其他的存在:
namespace matrixClass {
// BEGIN Forward declarations
template<class T>
class Matrix;
template<class U>
std::ostream &operator<<(std::ostream&, const Matrix<U> &matrix);
template<class U>
Matrix<U>* operator*(const Matrix<U> &m1, const Matrix<U> &m2);
// END Forward declarations
template<class T>
class Matrix
{
...
template<class U>
friend std::ostream &operator<<(std::ostream&, const Matrix<U> &matrix);
template<class U>
friend Matrix<U>* operator*(const Matrix<U> &m1, const Matrix<U> &m2);
};
...
template<class U>
std::ostream& operator<<(std::ostream& output, const Matrix<U>& matrix)
{
... // your implementation goes here
}
template<class U>
Matrix<U>* operator*(const Matrix<U>& m1, const Matrix<U>& m2)
{
... // your implementation goes here
}
} // end of namespace matrixClass
所有这些模板代码都应该在头文件中,Matrix.h,因为已经提到了。
此外,我认为您应该将 operator*()
的原型更改为 return Matrix<U>
而不是 Matrix<U>*
。它的行为更像普通的 operator*()
,并且可以让您执行以下操作:Matrix<int> m = m1*m2;
或 m = m1*m2*m3;
。此外,class 的用户不必担心删除 operator*()
分配的内存或动态分配的性能成本。只需在 operator*()
和 return 中按值创建一个本地 Matrix<U>
变量;让 Return 价值优化 (RVO) 处理剩下的事情。
我的 C++ 代码示例中有一个大问题。 'friend' 和 'template'.
错误信息:
Matrix.h:26:79: 警告:
friend declaration 'std::ostream& matrixClass::operator<<(std::ostream&, const matrixClass::Matrix&)' declares a non-template function [-Wnon-template-friend] friend std::ostream &operator<<(std::ostream&, const Matrix &matrix);
Matrix.h:26:79: 注:
(if this is not what you intended, make sure the function template
has already been declared and add <> after the function name here)
Matrix.h:28:77:警告:
friend declaration 'matrixClass::Matrix<T>*
matrixClass::operator*(const matrixClass::Matrix&, const matrixClass::Matrix&)' declares a non-template function [-Wnon-template-friend] friend Matrix* operator*(const Matrix &m1, const Matrix &m2);
Matrix.cpp:1:0:
C:\Users\Peter\CLionProjects\PK\untitled76\Matrix.h:26:79: warning: friend declaration 'std::ostream& matrixClass::operator<<(std::ostream&, const matrixClass::Matrix&)' declares a non-template function [-Wnon-template-friend] friend std::ostream &operator<<(std::ostream&, const Matrix &matrix);
Matrix.h:26:79: 注:
(if this is not what you intended, make sure the function template
has already been declared and add <> after the function name here)
Matrix.h:28:77:警告:
friend declaration 'matrixClass::Matrix<T>*
matrixClass::operator*(const matrixClass::Matrix&, const matrixClass::Matrix&)' declares a non-template function [-Wnon-template-friend] friend Matrix* operator*(const Matrix &m1, const Matrix &m2);
CMakeFiles\untitled76.dir/objects.a(main.cpp.obj): 在函数`main'中:
main.cpp:8: 未定义引用
main.cpp:8: 对 matrixClass::Matrix<int>::Matrix(int)'<br>
main.cpp:10: undefined reference to
matrixClass::Matrix::set(int, int, int)'
的未定义引用
main.cpp:11: 对 matrixClass::Matrix<int>::set(int, int, int)'<br>
main.cpp:12: undefined reference to
matrixClass::Matrix::set(int, int, int)'
的未定义引用
main.cpp:13: 对 matrixClass::Matrix<int>::set(int, int, int)'<br>
main.cpp:15: undefined reference to
matrixClass::operator<<(std::ostream&, matrixClass::Matrix const&)'
的未定义引用
main.cpp:15: 对 matrixClass::operator<<(std::ostream&, matrixClass::Matrix<int> const&)'<br>
main.cpp:8: undefined reference to
matrixClass::Matrix::~Matrix()'
的未定义引用
main.cpp:8: 未定义引用`matrixClass::Matrix::~Matrix()'
代码: Matrix.h
#ifndef MATRIX_H_
#define MATRIX_H_
#include <iostream>
namespace matrixClass {
template<class T>
class Matrix {
private:
int dimension;
T **m;
public:
Matrix(int d);
Matrix(const Matrix &original);
~Matrix();
void set(int x, int y, T value);
T get(int x, int y) const;
int getDimension() const;
friend std::ostream &operator<<(std::ostream&, const Matrix<T> &matrix);
friend Matrix<T>* operator*(const Matrix<T> &m1, const Matrix<T> &m2);
};
}
#endif
Matrix.cpp
#include "Matrix.h"
using namespace matrixClass;
template<class T>
Matrix<T>::Matrix(int d)
: dimension{d}, m{new T *[d]} {
//m = new T*[d];
for (int i = 0; i < d; i++) {
m[i] = new T[d];
}
}
// COPY-CONSTRUCTOR
template<class T>
Matrix<T>::Matrix(const Matrix &original)
: dimension{original.dimension},
m{new T *[original.dimension]} {
for (int i = 0; i < dimension; i++) {
*(m + i) = *(original.m + i);
}
}
// DESTRUCTOR
template<class T>
Matrix<T>::~Matrix() {
for (int i = 0; i < dimension; i++) {
delete[] m[i];
}
delete[] m;
}
template<class T>
void Matrix<T>::set(int x, int y, T value) {
m[x][y] = value;
}
template<class T>
T Matrix<T>::get(int x, int y) const {
return m[x][y];
}
template<class T>
int Matrix<T>::getDimension() const {
return dimension;
}
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix) {
int dimension = matrix.getDimension();
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
output << matrix.get(x, y) << " ";
}
return output;
}
}
template<class T>
Matrix<T>* operator*(const Matrix<T>& m1, const Matrix<T>& m2) {
int dimension = m1.getDimension();
Matrix<T>* m = new Matrix<T>(dimension);
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
T value = 0;
for(int i = 0; i < dimension; i++) {
value += m1.get(x, i) * m2.get(i, y);
}
m->set(x, y, value);
}
}
return m;
}
main.cpp
#include <iostream>
#include "Matrix.h"
using namespace matrixClass;
using namespace std;
int main() {
Matrix<int> m(2);
m.set(0, 0, 1);
m.set(0, 1, 2);
m.set(1, 0, 3);
m.set(1, 1, 4);
cout << m << "*" << endl << m << "=" << endl;
return 0;
}
在friend
声明中operator<<
引用了一个非模板函数,而它的定义说它是一个模板函数;他们不匹配。
您可以在 friend
声明中内联定义它(作为非模板函数):
template<class T>
class Matrix {
... ...
friend std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix) {
int dimension = matrix.getDimension();
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
output << matrix.get(x, y) << " ";
}
return output;
}
}
... ...
};
或者friend
声明引用函数模板:
// class declaration
template<class T>
class Matrix;
// function declaration
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix);
// class definition
template<class T>
class Matrix {
... ...
friend std::ostream& operator<< <T>(std::ostream& output, const Matrix<T>& matrix);
... ...
};
// function definition
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix) {
int dimension = matrix.getDimension();
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
output << matrix.get(x, y) << " ";
}
return output;
}
}
关于未定义引用错误,参见Why can templates only be implemented in the header file?
此答案解决了您的非成员 operator<<()
和 operator*()
使用好友模板的问题,这与将函数模板的实例设为好友略有不同(第二个解决方案由@宋元尧)。不同之处在于,使用友元模板时,模板函数的所有实例都是 class Matrix<>
的友元。在这种情况下,我认为没有任何实际差异,但在其他情况下,可能会有。因此,我想无论如何我都会展示它。
我是这样想的。这两个运算符都是非成员函数,这意味着它们独立于 class Matrix<>
,因此请独立考虑它们的原型:
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix);
template<class T>
Matrix<T>* operator*(const Matrix<T>& m1, const Matrix<T>& m2);
现在,将 T
替换为 U
,因为要使它们的所有实例成为 Matrix<>
的朋友,它们的原型需要包含在 class 定义中 Matrix<>
这也是一个模板,它已经使用 T
作为它的模板参数。
template<class U>
std::ostream& operator<<(std::ostream& output, const Matrix<U>& matrix);
template<class U>
Matrix<U>* operator*(const Matrix<U>& m1, const Matrix<U>& m2);
现在,您可以让他们成为 Matrix<>
的朋友。您只需要适当的语法:
template<class T>
class Matrix
{
...
template<class U>
friend std::ostream &operator<<(std::ostream&, const Matrix<U> &matrix);
template<class U>
friend Matrix<U>* operator*(const Matrix<U> &m1, const Matrix<U> &m2);
};
最后,它们都需要在 matrixClass
namespace
内,并且它们的声明和定义需要以正确的顺序排列,以便每个人都知道其他的存在:
namespace matrixClass {
// BEGIN Forward declarations
template<class T>
class Matrix;
template<class U>
std::ostream &operator<<(std::ostream&, const Matrix<U> &matrix);
template<class U>
Matrix<U>* operator*(const Matrix<U> &m1, const Matrix<U> &m2);
// END Forward declarations
template<class T>
class Matrix
{
...
template<class U>
friend std::ostream &operator<<(std::ostream&, const Matrix<U> &matrix);
template<class U>
friend Matrix<U>* operator*(const Matrix<U> &m1, const Matrix<U> &m2);
};
...
template<class U>
std::ostream& operator<<(std::ostream& output, const Matrix<U>& matrix)
{
... // your implementation goes here
}
template<class U>
Matrix<U>* operator*(const Matrix<U>& m1, const Matrix<U>& m2)
{
... // your implementation goes here
}
} // end of namespace matrixClass
所有这些模板代码都应该在头文件中,Matrix.h,因为已经提到了。
此外,我认为您应该将 operator*()
的原型更改为 return Matrix<U>
而不是 Matrix<U>*
。它的行为更像普通的 operator*()
,并且可以让您执行以下操作:Matrix<int> m = m1*m2;
或 m = m1*m2*m3;
。此外,class 的用户不必担心删除 operator*()
分配的内存或动态分配的性能成本。只需在 operator*()
和 return 中按值创建一个本地 Matrix<U>
变量;让 Return 价值优化 (RVO) 处理剩下的事情。