当前位置: 首页 > 知识库问答 >
问题:

C++中的朋友和模板

米项禹
2023-03-14

我的C++代码示例中有一个很大的问题。“朋友”和“模板”有问题。

错误消息:
Matrix.h:26:79:警告:

友元声明'std::oStream&MatrixClass::Operator<<(std::oStream&,const MatrixClass::Matrix&)'声明一个非模板函数[-wnon-template-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

已声明,并在此处的函数名后添加<>)

Matrix.H:28:77:警告:

  friend declaration 'matrixClass::Matrix<T>*

MatrixClass::Operator*(const MatrixClass::Matrix&,const MatrixClass::Matrix&)'声明一个非模板函数[-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:警告:友元声明'std::ostream&matrixclass::operator<<(std::ostream&,const matrixclass::Matrix&)'声明了一个非模板函数[-wnon-template-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

已声明,并在此处的函数名后添加<>)

Matrix.H:28:77:警告:

  friend declaration 'matrixClass::Matrix<T>*

MatrixClass::Operator*(const MatrixClass::Matrix&,const MatrixClass::Matrix&)'声明一个非模板函数[-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 ::Matrix(int)“
Main.cpp:10:未定义对
MatrixClass::Matrix::Matrix::Set(int,int,int)”
Main.cpp:11:未定义对MatrixClass::Matrix ::Set(int,int,int)“
Main.cpp:12:未定义对
MatrixClass::Matrix::Matrix ::Set(int,int,int)”

代码: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;
}

共有2个答案

孔寒
2023-03-14

这个答案解决了您的非成员运算符<<()运算符*()使用好友模板的问题,这与使函数模板的实例成为好友(@songyuanyao提供的第二种解决方案)略有不同。不同之处在于,使用Friend模板时,Template函数的所有实例都是类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<>的朋友,它们的原型需要包含在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);

现在,您可以让他们成为矩阵<>的朋友。您所需要的只是适当的语法:

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 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中,前面已经提到过。

此外,我认为您应该更改运算符*()的原型,以返回矩阵而不是矩阵*。它的行为将更像普通的运算符*(),并且它将使您能够执行以下操作:矩阵 m=m1*m2; m=m1*m2*m3;。此外,您的类的用户不必担心删除运算符*()分配的内存,也不必担心动态分配的性能开销。只需在operator*()中创建一个局部矩阵变量并按值返回;让返回值优化(RVO)来处理其余部分。

呼延钱明
2023-03-14

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;
    }
}

以及关于未定义引用错误,请参见为什么模板只能在头文件中实现?

 类似资料:
  • 为了了解在朋友关系中使用Neo4J的优势,我在MySQL数据库上创建了一个Persons表(“Persons”,20900个数据集): 和一张关系表(“友谊”,每个人有50到100个朋友): 因此,大约有120万人的关系。 现在我想查看id=1的人的朋友的朋友的朋友的朋友,因此我创建了一个如下查询: 用户ID 1的查询用了大约30秒 在Neo4J中,我为每个人创建了一个节点(20900个节点)和一

  • 问题内容: 我有一个类似于myspace / facebook的社交网络。在我的代码中,您不是一个人的朋友,还是不是一个朋友,因此,我显示了您与之成为朋友的人的所有操作(在此帖子中,我将这些操作单独称为公告帖子,以使其更易于可视化。 因此,您每当有人发布公告时,都会向在那里的任何朋友显示。 在mysql中,您可以通过执行以下操作来获得个人朋友列表, 我想知道像facebook之类的网站如何显示您的

  • 来自Lippman et al C Primer第5版,第16.1.2节: 第一个问题:排队 为什么是<代码> 我添加了以下代码来定义运算符==并实例化类模板。它成功编译和链接: 如果我删除

  • 我试图使乘法运算符成为名为TVector3的模板类的朋友。我读过,我可以在类声明中声明朋友函数之前,对其进行前向声明,但我这样做的尝试是徒劳的。我知道我可以简单地定义friend函数而不是声明它,但我希望它能与前向声明技术一起工作。 特别是,我试图为我的案例实施这个解决方案。我发现这篇文章也是David Rodriguez给出的解决方案(第三个版本),但我不知道我做错了什么。 我使用'g temp

  • 问题内容: 我正在尝试从用户表中提取数据,并且需要“朋友之友”,这些人与所选用户相距两步 但未直接连接到所选用户 我尝试了以下查询: 我不知道如何拉未直接连接到所选用户的用户。我得到了当前用户的朋友的所有朋友,但是我 也 得到了当前用户的直接朋友。 问题答案: 您只需要排除既是直接朋友又是朋友的人。我已经重新排列了表别名,这样(无论如何对我来说)就更清楚了要检索的内容: 它还消除了排除要查询的用户

  • 我无法让它工作: 无法编译,错误消息如下: 无效使用temping-id'运算符*