首页 文章

C中的朋友和模板

提问于
浏览
6

我的C代码示例中存在一个大问题 . 'friend'和'template'有问题 .

Error Messages:
Matrix.h:26:79:警告:

friend declaration'std :: ostream&matrixClass :: operator <<(std :: ostream&,const matrixClass :: Matrix&)'声明一个非模板函数[-Wnon-template-friend] friend std :: ostream&operator <<( std :: ostream&,const Matrix&matrix);

Matrix.h:26:79:注意:

(如果这不是您的意图,请确保功能模板
已经声明并在函数名后添加<>)

Matrix.h:28:77:警告:

朋友声明'matrixClass :: Matrix <T> *
matrixClass :: operator *(const matrixClass :: Matrix&,const matrixClass :: Matrix&)'声明非模板函数[-Wnon-template-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] friend std :: ostream&operator <<(std :: ostream&,const Matrix&matrix);

Matrix.h:26:79:注意:

(如果这不是您的意图,请确保功能模板
已经声明并在函数名后添加<>)

Matrix.h:28:77:警告:

朋友声明'matrixClass :: Matrix <T> *
matrixClass :: operator *(const matrixClass :: Matrix&,const matrixClass :: Matrix&)'声明非模板函数[-Wnon-template-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()'

Code: 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 回答

  • 5

    friend 声明 operator<< 指的是非模板函数,而它的定义表示's a template function; they don' t匹配 .

    您可以使用 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?

  • 0

    这个答案解决了你的非成员 operator<<()operator*() 使用好友模板的问题,这与将一个功能模板的实例作为朋友(由@songyuanyao提供的第二个解决方案)略有不同 . 区别在于使用好友模板,模板功能的所有实例都是类 Matrix<> 的朋友 . 在这种情况下,无论如何我都不会出现它 .

    我想是这样的 . 两个运算符都是非成员函数,这意味着它们独立于类 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);
    

    现在,你可以让他们成为 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*() 的原型以返回 Matrix<U> 而不是 Matrix<U>* . 它的行为更像普通的 operator*() ,它可以让你做的事情如下: Matrix<int> m = m1*m2;m = m1*m2*m3; . 此外,您的类的用户不必担心删除 operator*() 分配的内存或动态分配的性能成本 . 只需在 operator*() 中创建一个本地 Matrix<U> 变量并按值返回;让返回值优化(RVO)处理其余的事情 .

相关问题