[笔记]《Essential C++》第六章习题6.2

题目

练习 6.2重新以template形式实现练习4.3的Matrix class,并扩充其功能,使它能够通过heap memory(堆内存)来支持任意行列大小。分配/释放内存的操作,请在constructor/destructor中进行。

书中习题解答给出的代码

#include <iostream>
#include<fstream>

using namespace std;

template <typename elemType>
class Matrix
{
    friend Matrix<elemType>
    operator+(const Matrix<elemType> &, const Matrix<elemType> &);

    friend Matrix<elemType>
    operator*(const Matrix<elemType> &, const Matrix<elemType> &);

public:
    Matrix(int rows, int columns) : _rows(rows), _cols(columns)
    {
        int size = _rows*_cols;
        _matrix = new elemType[size];
        for(int ix = 0; ix < size; ++ix)
        {
            _matrix[ix] = elemType();
        }
    }
    Matrix(const Matrix&);
    ~Matrix(){ delete[] _matrix;}
    Matrix& operator=(const Matrix&);

    void operator+=(const Matrix&);

    elemType& operator() (int row, int column){return _matrix[row*cols() + column];}

    const elemType& operator() (int row, int column) const{return _matrix[row*cols() +column];}

    int rows() const{return _rows;}
    int cols() const{return _cols;}

    bool same_size(const Matrix &m) const{return rows() == m.rows() && cols() == m.cols();}

    bool comfortable(const Matrix &m) const{return (cols() == m.rows());}

    ostream& print(ostream&) const;

protected:
    int _rows;
    int _cols;
    elemType *_matrix;
};

template <typename elemType>
inline ostream& operator<<(ostream& os, const Matrix<elemType> &m)
{
    return m.print(os);
}

// Matrix.h文件结束

template <typename elemType>
Matrix<elemType>
operator+(const Matrix<elemType> &m1, const Matrix<elemType> &m2)
{
    // 确认m1和m2的大小相同
    Matrix<elemType> result(m1);
    result += m2;
    return result;
}

template <typename elemType>
Matrix<elemType>
operator*(const Matrix<elemType> &m1, const Matrix<elemType> &m2)
{
    // m1的行数(row)必须等于m2的列数(column)
    Matrix<elemType> result(m1.rows(), m2.cols());
    for(int ix = 0; ix < m1.rows(); ++ix)
    {
        for(int jx = 0; jx < m2.rows(); ++jx)
        {
            result(ix, jx) = 0;

            for(int kx = 0; kx < m1.cols(); ++kx)
            {
                result(ix, jx) += m1(ix, kx) * m2(kx, jx);
            }
        }
    }
    return result;
}

template <typename elemType>
Matrix<elemType>::Matrix(const Matrix &rhs)
{
    _rows = rhs._rows;
    _cols = rhs._cols;
    int mat_size = _rows*_cols;
    _matrix = new elemType[mat_size];
    for(int ix = 0; ix < mat_size; ++ix)
    {
        _matrix[ix] = rhs._matrix[ix];
    }
}

template <typename elemType>
Matrix<elemType>& Matrix<elemType>::operator=(const Matrix &rhs)
{
    // 确认m1和m2的大小相同
    if(this != &rhs)
    {
        _rows = rhs._rows;
        _cols = rhs._cols;
        int mat_size = _rows*_cols;
        delete[] _matrix;
        _matrix = new elemType[mat_size];
        for(int ix = 0; ix < mat_size; ++ix)
        {
            _matrix[ix] = rhs._matrix[ix];
        }
    }
    return *this;
}

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

template <typename elemType>
ostream& Matrix<elemType>::print(ostream &os) const
{
    int col = cols();
    int matrix_size = col*rows();
    for(int ix = 0; ix < matrix_size; ++ix)
    {
        if(ix % col == 0) os << endl;
        os << (*(_matrix + ix)) << ' ';
    }
    os << endl;
    return os;
}

int main()
{
    ofstream log("log.txt");
    if(!log)
    {
        cerr << "can't open log file!\n";
        return 0;
    }

    Matrix<float> identity(4, 4);
    log << "identity: " << identity << endl;
    float ar[16] = {1., 0., 0., 0., 0., 1., 0., 0.,
                    0., 0., 1., 0., 0., 0., 0., 1. };

    for(int i = 0, k = 0; i < 4; ++i)
    {
        for(int j = 0; j < 4; ++j)
        {
            identity(i, j) = ar[k++];
        }
    }
    log << "identity after set: " << identity << endl;

    Matrix<float> m(identity);
    log << "m: memberwise initialized: " << m << endl;

    Matrix<float> m2(8, 12);
    log << "m2: 8x12: " << m2 << endl;

    m2 = m;
    log << "m2 after memberwise assigned to m: " << m2 << endl;

    float ar2[16] = {1.3, 0.4, 2.6, 8.2, 6.2, 1.7, 1.3, 8.3,
                     4.2, 7.4, 2.7, 1.9, 6.3, 8.1, 5.6, 6.6 };

    Matrix<float> m3(4,4);
    for(int i = 0, k = 0; i < 4; ++i)
    {
        for(int j = 0; j < 4; ++j)
        {
            m3(i, j) = ar2[k++];
        }
    }
    log << "m3: assigned random values: " << m3 << endl;

    Matrix<float> m4 = m3*identity;
    log << "result of m3*identity: " << m4 << endl;

    Matrix<float> m5 = m3 + m4;
    log << "result of m3 + m4: " << m5 << endl;

    m3 += m4;
    log << "m3: plus with m4: " << m3 << endl;
}

在我运行上面的程序之后,编译器直接报错,报错信息是

undefined reference to `operator*(Matrix<float> const&, Matrix<float> const&)'

以及

undefined reference to `operator+(Matrix<float> const&, Matrix<float> const&)'

这两个函数是Matrix的友元函数,按理说将其声明写在类定义中,定义写在外面应该是可以的,但是注意,在上面的类定义中,并没有声明这两个友元函数是模板函数,但是在后面的定义中,用的却是模板函数的定义,所以我们只要在声明时加上模板就行了,注意不要用和Matrix的模板参数名称一样的模板参数名,会导致下面的编译错误:

error: declaration of template parameter 'elemType' shadows template parameter

正确代码

#include <iostream>
#include<fstream>

using namespace std;

template <typename elemType>
class Matrix
{
    template <typename T>
    friend Matrix<T>
    operator+(const Matrix<T> &, const Matrix<T> &);

    template <typename T>
    friend Matrix<T>
    operator*(const Matrix<T> &, const Matrix<T> &);

public:
    Matrix(int rows, int columns) : _rows(rows), _cols(columns)
    {
        int size = _rows*_cols;
        _matrix = new elemType[size];
        for(int ix = 0; ix < size; ++ix)
        {
            _matrix[ix] = elemType();
        }
    }
    Matrix(const Matrix&);
    ~Matrix(){ delete[] _matrix;}
    Matrix& operator=(const Matrix&);

    void operator+=(const Matrix&);

    elemType& operator() (int row, int column){return _matrix[row*cols() + column];}

    const elemType& operator() (int row, int column) const{return _matrix[row*cols() +column];}

    int rows() const{return _rows;}
    int cols() const{return _cols;}

    bool same_size(const Matrix &m) const{return rows() == m.rows() && cols() == m.cols();}

    bool comfortable(const Matrix &m) const{return (cols() == m.rows());}

    ostream& print(ostream&) const;

protected:
    int _rows;
    int _cols;
    elemType *_matrix;
};

template <typename elemType>
inline ostream& operator<<(ostream& os, const Matrix<elemType> &m)
{
    return m.print(os);
}

// Matrix.h文件结束

template <typename elemType>
Matrix<elemType>
operator+(const Matrix<elemType> &m1, const Matrix<elemType> &m2)
{
    // 确认m1和m2的大小相同
    Matrix<elemType> result(m1);
    result += m2;
    return result;
}

template <typename elemType>
Matrix<elemType>
operator*(const Matrix<elemType> &m1, const Matrix<elemType> &m2)
{
    // m1的行数(row)必须等于m2的列数(column)
    Matrix<elemType> result(m1.rows(), m2.cols());
    for(int ix = 0; ix < m1.rows(); ++ix)
    {
        for(int jx = 0; jx < m2.rows(); ++jx)
        {
            result(ix, jx) = 0;

            for(int kx = 0; kx < m1.cols(); ++kx)
            {
                result(ix, jx) += m1(ix, kx) * m2(kx, jx);
            }
        }
    }
    return result;
}

template <typename elemType>
Matrix<elemType>::Matrix(const Matrix &rhs)
{
    _rows = rhs._rows;
    _cols = rhs._cols;
    int mat_size = _rows*_cols;
    _matrix = new elemType[mat_size];
    for(int ix = 0; ix < mat_size; ++ix)
    {
        _matrix[ix] = rhs._matrix[ix];
    }
}

template <typename elemType>
Matrix<elemType>& Matrix<elemType>::operator=(const Matrix &rhs)
{
    // 确认m1和m2的大小相同
    if(this != &rhs)
    {
        _rows = rhs._rows;
        _cols = rhs._cols;
        int mat_size = _rows*_cols;
        delete[] _matrix;
        _matrix = new elemType[mat_size];
        for(int ix = 0; ix < mat_size; ++ix)
        {
            _matrix[ix] = rhs._matrix[ix];
        }
    }
    return *this;
}

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

template <typename elemType>
ostream& Matrix<elemType>::print(ostream &os) const
{
    int col = cols();
    int matrix_size = col*rows();
    for(int ix = 0; ix < matrix_size; ++ix)
    {
        if(ix % col == 0) os << endl;
        os << (*(_matrix + ix)) << ' ';
    }
    os << endl;
    return os;
}

int main()
{
    ofstream log("log.txt");
    if(!log)
    {
        cerr << "can't open log file!\n";
        return 0;
    }

    Matrix<float> identity(4, 4);
    log << "identity: " << identity << endl;
    float ar[16] = {1., 0., 0., 0., 0., 1., 0., 0.,
                    0., 0., 1., 0., 0., 0., 0., 1. };

    for(int i = 0, k = 0; i < 4; ++i)
    {
        for(int j = 0; j < 4; ++j)
        {
            identity(i, j) = ar[k++];
        }
    }
    log << "identity after set: " << identity << endl;

    Matrix<float> m(identity);
    log << "m: memberwise initialized: " << m << endl;

    Matrix<float> m2(8, 12);
    log << "m2: 8x12: " << m2 << endl;

    m2 = m;
    log << "m2 after memberwise assigned to m: " << m2 << endl;

    float ar2[16] = {1.3, 0.4, 2.6, 8.2, 6.2, 1.7, 1.3, 8.3,
                     4.2, 7.4, 2.7, 1.9, 6.3, 8.1, 5.6, 6.6 };

    Matrix<float> m3(4,4);
    for(int i = 0, k = 0; i < 4; ++i)
    {
        for(int j = 0; j < 4; ++j)
        {
            m3(i, j) = ar2[k++];
        }
    }
    log << "m3: assigned random values: " << m3 << endl;

    Matrix<float> m4 = m3*identity;
    log << "result of m3*identity: " << m4 << endl;

    Matrix<float> m5 = m3 + m4;
    log << "result of m3 + m4: " << m5 << endl;

    m3 += m4;
    log << "m3: plus with m4: " << m3 << endl;
}
posted @   浮生的刹那  阅读(77)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
  1. 1 Night City r e l,Artemis Delta
  2. 2 Gold Steps(人生何处不青山) Neck Deep
  3. 3 Devil Trigger Ali Edwards
  4. 4 Hopeless Case Roam
  5. 5 On My Own Blitz Kids
  6. 6 I Really Want to Stay At Your House Rosa Walton & Hallie Coggins
  7. 7 Major Crimes Health & Window Weather
Night City - r e l,Artemis Delta
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.
点击右上角即可分享
微信分享提示