关于C++模板函数使用的一点心得记录

初次学习C++,对于C++和编译的具体原理也不懂,模板类的使用的时候遇到了许多坑,在此记录以备日后查阅

类模板函数连接出问题

  • 错误提示:
C:\Users\qsunj\AppData\Local\Temp\cc5VHYoh.o:main.cpp:(.text+0x12d): undefined reference to `Matrix<int>::operator+=(Matrix<int> const&)'
collect2.exe: error: ld returned 1 exit status
  • 源码(这里只详细贴出了出错部分的函数的信息,一些杂项被删去了):
//matrix.h
template <typename elemType>
class Matrix{
	public:
		/******************* constructor *********************/
		//created a new matrix
		Matrix( int rows, int columns )
			: _rows( rows ), _cols( columns )
		{
			int size = _rows * _cols;
			_matrix_data = new elemType[ size ];
			for ( int ix=0; ix<size; ++ix ) {
				_matrix_data[ ix ] = elemType();
			}
		}
		//copy a matrix
		Matrix( const Matrix &rhs )
		{
			_rows = rhs._rows;
			_cols = rhs._cols;
			int size = _rows * _cols;
			_matrix_data = new elemType[ size ];
			for ( int ix=0; ix<size; ++ix ) {
				_matrix_data[ ix ] = rhs._matrix_data[ ix ];
			}
		}

		/********** destructor <== Matrix(int,int) created static heap *********/
		~Matrix() { delete [] _matrix_data; }
		
		void print( const Matrix &rhs ) const
		{
			for (int row=0; row<_rows; row++) {
				cout << "|\t";
				for (int column=0; column<_cols; column++) {
					cout << rhs( row, column) << '\t';
				}
				cout << '|' << endl;
			}
		}
		int rows() const { return _rows; }
		int cols() const { return _cols; }
		
		Matrix& operator= ( const Matrix& );
		void operator+= ( const Matrix& );
		
		elemType& operator() ( int row, int column )
			{ return _matrix_data[ row*cols() + column ]; }
		const elemType& operator() ( int row, int column ) const
			{ return _matrix_data[ row*cols() + column ]; }

		bool is_same_size( const Matrix &m ) const
			{ return rows()==m.rows() && cols()==m.cols(); }
		
	private:
		int			_rows;
		int			_cols;
		elemType	*_matrix_data;
};

/**************************************************************************************
***************************************************************************************/

//matrix.cpp
template< typename elemType>
void Matrix<elemType>::operator+= ( const Matrix<elemType> &m )
{
	if ( this.is_same_size(m) ) {
		for ( int matrix_size=m.rows()*m.cols(), ix=0; ix<matrix_size; ix++ ) {
			_matrix_data[ix] += m._matrix_data[ix];
		}
	}
}

/**************************************************************************************
***************************************************************************************/

//main.cpp
#include "pratice0602.h"

int main()
{
	Matrix<int> m1(4, 4);
	Matrix<int> m2(4, 4);

	cout << "m1:" << endl;
	m1.print( m1 );
	cout << "m2:" << endl;
	m1.print( m2 );

	m1(0,0) = 1;
	m1(3,3) = 1;
	cout << "m1:" << endl;
	m1.print( m1 );
	m2 = m1;
	m2 += m2;
	cout << "m2:" << endl;
	m1.print( m2 );

	return 0;
}

原因及解决方法

  • 解决方法
    1.将模板函数的实现写在类中
    2.将实现函数的cpp文件一起包含在main.cpp中(例:#include “matrix.h”)

    个人比较倾向于方法1,方法2有时会出问题,也没仔细研究了

  • 原因:
    当一个模板不被用到的时侯它就不该被实例化出来;上面代码中编译main.cpp的时候用到了模板(在连接之前),但此时模板函数的定义在matrix.cpp中,而且两个文件是分开编译的,也就是说此时main.cpp想实现模板函数却找不到定义,自然报错“undefined reference to”(未定义)了。
  • 更详细的说明进请看这位大佬
    模板函数(template function)出现编译链接错误(link error)之解析

类模板友元函数出问题

  • 错误提示:
In file included from main.cpp:1:
pratice0602.h:10:64: warning: friend declaration 'Matrix<elemType> operator+(const Matrix<elemType>&, const Matrix<elemType>&)' declares a non-template function [-Wnon-template-friend]
   operator+ ( const Matrix<elemType>&, const Matrix<elemType>& );
                                                                ^
pratice0602.h:10:64: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) 
C:\Users\qsunj\AppData\Local\Temp\cciEqvMa.o:main.cpp:(.text+0x134): undefined reference to `operator+(Matrix<int> const&, Matrix<int> const&)'
collect2.exe: error: ld returned 1 exit status

  • 源码(这里只详细贴出了出错部分的函数的信息,一些杂项被删去了):
//matrix.h
template <typename elemType>
class Matrix{
	friend Matrix<elemType>
		operator+ ( const Matrix<elemType>&, const Matrix<elemType>& );

	public:
		/******************* constructor *********************/
		//created a new matrix
		Matrix( int rows, int columns )
			: _rows( rows ), _cols( columns )
		{
			int size = _rows * _cols;
			_matrix_data = new elemType[ size ];
			for ( int ix=0; ix<size; ++ix ) {
				_matrix_data[ ix ] = elemType();
			}
		}
		//copy a matrix
		Matrix( const Matrix &rhs )
		{
			_rows = rhs._rows;
			_cols = rhs._cols;
			int size = _rows * _cols;
			_matrix_data = new elemType[ size ];
			for ( int ix=0; ix<size; ++ix ) {
				_matrix_data[ ix ] = rhs._matrix_data[ ix ];
			}
		}

		/********** destructor <== Matrix(int,int) created static heap *********/
		~Matrix() { delete [] _matrix_data; }
		
		
		void print( const Matrix &rhs ) const
		{
			for (int row=0; row<_rows; row++) {
				cout << "|\t";
				for (int column=0; column<_cols; column++) {
					cout << rhs( row, column) << '\t';
				}
				cout << '|' << endl;
			}
		}
		int rows() const { return _rows; }
		int cols() const { return _cols; }
		
		Matrix& operator= ( const Matrix& );
		void operator+= ( const Matrix& );
		
		elemType& operator() ( int row, int column )
			{ return _matrix_data[ row*cols() + column ]; }
		const elemType& operator() ( int row, int column ) const
			{ return _matrix_data[ row*cols() + column ]; }

		bool is_same_size( const Matrix &m ) const
			{ return rows()==m.rows() && cols()==m.cols(); }
		
	private:
		int			_rows;
		int			_cols;
		elemType	*_matrix_data;
};

template< typename elemType>
Matrix<elemType>& Matrix<elemType>::operator= ( const Matrix &m )
{
	if ( this->_matrix_data != m._matrix_data ) {
		_rows = m.rows();
		_cols = m.cols();
		int matrix_size = _rows*_cols;
		delete [] _matrix_data;
		_matrix_data = new elemType[ matrix_size ];
		for ( int ix=0; ix<matrix_size; ix++ ) {
			_matrix_data[ix] = m._matrix_data[ix];
		}
	}
	
	return *this;
}

template< typename elemType>
void Matrix<elemType>::operator+= ( const Matrix<elemType> &m )
{
	if ( rows()==m.rows() && cols()==m.cols() ) {
		for ( int matrix_size=m.rows()*m.cols(), ix=0; ix<matrix_size; ix++ ) {
			_matrix_data[ix] += m._matrix_data[ix];
		}
	}
}

template< typename elemType>
Matrix<elemType> operator+ ( const Matrix<elemType> &m1, const Matrix<elemType> &m2 )
{
	Matrix<elemType> result( m1 );
	result += m2;
	return result;
}

/**************************************************************************************
***************************************************************************************/

//main.cpp
int main()
{
	Matrix<int> m1(4, 4);
	Matrix<int> m2(4, 4);

	cout << "m1:" << endl;
	m1.print( m1 );
	cout << "m2:" << endl;
	m1.print( m2 );

	m1(0,0) = 1;
	m1(3,3) = 1;
	cout << "m1:" << endl;
	m1.print( m1 );
	m2 = m1;
	m2 = m1 + m2;
	cout << "m2:" << endl;
	m1.print( m2 );

	return 0;
}

原因及解决方法

  • 解决方法(并非全部):
    1.将模板友元函数的实现写在类中(下面是例子)
    friend Matrix<elemType>
      operator+ ( const Matrix<elemType>&, const Matrix<elemType>& )
      {
      	Matrix<elemType> result( m1 );
      	result += m2;
      	return result;
      }
    
    2.将模板友元函数的template与类的template显式的分开(下面是例子)
    template< typename freType>
      friend Matrix<freType>
      	operator+ ( const Matrix<freType>&, const Matrix<freType>& );
    
  • 原因:
    错误提示中提到"declares a non-template function"==>模板友元函数并没有被我所认为的那样被声明成了模板函数,由于我目前还不会用template< class T>这种模板,理解也不大行,具体原因请看大佬们的博客:模板类的友元函数

关于源码的来源:

  • 环境:VSCode C++
  • 源码来源: Essential C++联系题
  • 简单的成功实现的源码:
//.h文件
#ifndef __PRATICE0602_H
#define __PRATICE0602_H

#include <iostream>
using namespace std;

template <typename elemType>
class Matrix{
	template< typename freType>
	friend Matrix<freType>
		operator+ ( const Matrix<freType>&, const Matrix<freType>& );
	friend Matrix<elemType>
		operator* ( const Matrix<elemType>&m1, const Matrix<elemType>&m2 )
		{
			Matrix<elemType> result( m1.rows(), m2.cols());
			for ( int ix=0; ix<4; ix++) {
				for ( int jx=0; jx<4; jx++ ) {
					result( ix, jx ) = 0;
					for ( int kx=0; kx<4; kx++ )
						result( ix, jx ) += m1(ix, kx) * m2(kx, jx);
				}
			}
			return result;
		}
	public:
		/******************* constructor *********************/
		//created a new matrix
		Matrix( int rows, int columns )
			: _rows( rows ), _cols( columns )
		{
			int size = _rows * _cols;
			_matrix_data = new elemType[ size ];
			for ( int ix=0; ix<size; ++ix ) {
				_matrix_data[ ix ] = elemType();
			}
		}
		//copy a matrix
		Matrix( const Matrix &rhs )
		{
			_rows = rhs._rows;
			_cols = rhs._cols;
			int size = _rows * _cols;
			_matrix_data = new elemType[ size ];
			for ( int ix=0; ix<size; ++ix ) {
				_matrix_data[ ix ] = rhs._matrix_data[ ix ];
			}
		}

		/********** destructor <== Matrix(int,int) created static heap *********/
		~Matrix() { delete [] _matrix_data; }
		
		
		void print( const Matrix &rhs ) const
		{
			for (int row=0; row<_rows; row++) {
				cout << "|\t";
				for (int column=0; column<_cols; column++) {
					cout << rhs( row, column) << '\t';
				}
				cout << '|' << endl;
			}
		}
		int rows() const { return _rows; }
		int cols() const { return _cols; }
		
		Matrix& operator= ( const Matrix& );
		void operator+= ( const Matrix& );
		
		elemType& operator() ( int row, int column )
			{ return _matrix_data[ row*cols() + column ]; }
		const elemType& operator() ( int row, int column ) const
			{ return _matrix_data[ row*cols() + column ]; }

		bool is_same_size( const Matrix &m ) const
			{ return rows()==m.rows() && cols()==m.cols(); }
		
	private:
		int			_rows;
		int			_cols;
		elemType	*_matrix_data;
};

template< typename elemType>
Matrix<elemType>& Matrix<elemType>::operator= ( const Matrix &m )
{
	if ( this->_matrix_data != m._matrix_data ) {
		_rows = m.rows();
		_cols = m.cols();
		int matrix_size = _rows*_cols;
		delete [] _matrix_data;
		_matrix_data = new elemType[ matrix_size ];
		for ( int ix=0; ix<matrix_size; ix++ ) {
			_matrix_data[ix] = m._matrix_data[ix];
		}
	}
	
	return *this;
}

template< typename elemType>
void Matrix<elemType>::operator+= ( const Matrix<elemType> &m )
{
	if ( rows()==m.rows() && cols()==m.cols() ) {
		for ( int matrix_size=m.rows()*m.cols(), ix=0; ix<matrix_size; ix++ ) {
			_matrix_data[ix] += m._matrix_data[ix];
		}
	}
}

template< typename elemType>
Matrix<elemType> operator+ ( const Matrix<elemType> &m1, const Matrix<elemType> &m2 )
{
	Matrix<elemType> result( m1 );
	result += m2;
	return result;
}

#endif

/************************************************************************************************************************************************************************************/
//main.cpp文件
#include "pratice0602.h"

int main()
{
	Matrix<int> m1(4, 4);
	Matrix<int> m2(4, 4);

	cout << "m1:" << endl;
	m1.print( m1 );
	cout << "m2:" << endl;
	m1.print( m2 );

	m1(0,0) = 1;
	m1(3,3) = 1;
	cout << "m1:" << endl;
	m1.print( m1 );
	m2 = m1 + m1;
	cout << "m2 = m1 + m1:" << endl;
	m1.print( m2 );
	m2 = m2 * m2;
	cout << "m2 * m2:" << endl;
	m1.print( m2 );

	cout << "pratice0602 is running OK!" << endl;
	return 0;
}

如有错误请多指教

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值