数据结构大作业1:矩阵类的实现

第一次的数据结构大作业,代码量还是很足的,但其实实现思路上没有什么障碍,问题主要是对于c++的各种性质掌握的不够熟练,总是出现各种问题。

要求

在这里插入图片描述

Matrix.h

类的声明部分

//带有默认参数值的模板类成员不能在类外进行定义,修改方式有两种。
//模板类不能声明和定义分文件
#ifndef MATRIX_H
#define MATRIX_H
#include "Visit.h"
#include<cmath>

template <typename T> class Matrix{ //矩阵模板类
private: 
    int _row; int _col;
    T** _elem; //数据区
public:
    //构造函数
    Matrix(int r);//构造一个单位阵
    Matrix(int row, int col);//自己输入元素初始化
    Matrix(int row, int col, T v);
    Matrix(T **p,int row,int col);//一般不用
    Matrix(const Matrix<T> &obj);//拷贝构造函数
    //析构函数
    ~Matrix();
    //只读访问接口
    T Tabs(T m)  const{if(m < 0) return -m; else return m;}//计算绝对值
    int row() const{ return _row;}//返回行数
    int col() const{ return _col;}//返回列数
    Matrix<T> get_row(int row) const;//提取出第row行元素存放在额外一段连续空间,并返回该段空间对应的首地址
    Matrix<T> get_col(int col) const;//提取出第col列元素存放在额外一段连续空间,并返回该段空间对应的首地址
    Matrix<T> get_submatrix( int r_lo, int row, int c_lo, int col) const;//得到子矩阵,r_lo开始取row行,c_lo开始取col列
    Matrix<T> get_cofactor(int row,int col) const; //得到余子式,如四阶矩阵得到三阶矩阵,传入某元素所在的行列,去掉该行列剩余的合并
    T get_max() const;//返回矩阵中的最大元素,并且输出其所在的行数列数
    T get_min() const;//返回矩阵中的最小元素,并且输出其所在的行数列数
    T get_average() const;//返回矩阵中元素的平均值,并且输出与之最接近的元素及所在的行数列数
    bool search(T const& e) const;//在矩阵中查找元素
    bool search_row(int row,T const& e) const;//在矩阵中某行查找元素
    bool search_col(int col,T const& e) const;//在矩阵中某列查找元素
    //可写接口
    //遍历
    template <typename VST> void traverse(VST&) const;//遍历(使用函数对象,可全局性修改)
    void traverse();
    Matrix<T>& insert_row(int row,T *p);//在第row行后面插入一行
    Matrix<T>& insert_col(int col,T *p);//在第col列后面插入一列
    Matrix<T>& remove_row(int row);//删除某行
    Matrix<T>& remove_col(int col);//删除某列
    //矩阵运算
    T Det() const;//求行列式的值//递归调用det
    Matrix<T> Transpose() const;//求转置矩阵
    Matrix<T> Adjoint() const;//求伴随矩阵
    Matrix<T> Flips() const;//矩阵各个元素值取反,则可以通过取反后的矩阵结合矩阵乘法实现矩阵减法(涉及到A-B还是B-A)
    Matrix<T> Inverse() const;//矩阵求逆,结合矩阵乘法实现矩阵除法
    Matrix<T> operator+(Matrix<T> const&) const;//矩阵之间的+操作
    Matrix<T> operator-(Matrix<T> const&) const;//矩阵之间的-操作
    Matrix<T> operator*(Matrix<T> const&) const;//矩阵之间的*操作
    Matrix<T> operator/(Matrix<T> const&) const;//矩阵之间的/操作
    Matrix<T> operator+(T) const;//矩阵和标量的+操作
    Matrix<T> operator-(T) const;//矩阵和标量之间的-操作
    Matrix<T> operator*(T) const;//矩阵和标量之间的*操作
    Matrix<T> operator/(T) const;//矩阵和标量之间的/操作
};

类的实现部分

template<typename T> 
Matrix<T>::Matrix(int r):_row(r),_col(r){ //构造一个r*r的单位阵
    _elem = new T*[r];
    for (int i = 0; i < r; i++) {
        _elem[i] = new T[r];
    } //二维数组动态分配内存的构造方法
    for(int i = 0;i < r;i++){
        for(int j = 0;j < r;j++){
            if(i == j) _elem[i][j] = 1;
            else _elem[i][j] = 0;
        }
    } 
}
template<typename T> 
Matrix<T>::Matrix(int row, int col, T v) :_row(row),_col(col){ //构造的矩阵的行数和列数
    _elem = new T*[_row];
    for (int i = 0; i < _row; i++) {
        _elem[i] = new T[_col];
    } //二维数组动态分配内存的构造方法
    for(int i = 0;i < _row;i++){
        for(int j = 0;j < _col;j++){
            _elem[i][j] = v;
        }
    }    
}
template<typename T> 
Matrix<T>::Matrix(int row, int col) :_row(row),_col(col){ //自己输入矩阵元素构造函数
    _elem = new T*[_row];
    for (int i = 0; i < _row; i++) {
        _elem[i] = new T[_col];
    }
    std::cout << "请输入" << _row <<"x"<<_col<<"的矩阵"<<std::endl;
    for(int i = 0;i < _row;i++){
        for(int j = 0;j < _col;j++){
            std::cin >> _elem[i][j];
        }
    }
}
template<typename T> 
Matrix<T>::Matrix(T **p,int row,int col):_row(row),_col(col){ //通过动态二维数组构造函数
    _elem = new T*[_row];
    for (int i = 0; i < _row; i++) {
        _elem[i] = new T[_col];
    }
    for(int i = 0;i < _row;i++){
        for(int j = 0;j < _col;j++){
            _elem[i][j] = p[i][j];    
        }
    }
}
template<typename T> 
Matrix<T>::Matrix(const Matrix<T> &obj):_row(obj._row),_col(obj._col){//拷贝构造函数
    _elem = new T*[_row];
    for (int i = 0; i < _row; i++) {
        _elem[i] = new T[_col];
    }
    for(int i = 0;i < _row;i++){
        for(int j = 0;j < _col;j++){
            _elem[i][j] = obj._elem[i][j];//把元素复制过去
        }
    }  
}
template<typename T> 
Matrix<T>::~Matrix(){
    for(int i=0;i < _row;i++)
        delete[] _elem[i];
    delete[] _elem;
}//二维数组释放内存。注意释放内存是传入的地址,即该地址对应的内存块,且new时指向该内存块
template<typename T>
bool Matrix<T>::search(T const& e) const{
    for(int i = 0;i<_row;i++){
        for(int j = 0;j<_col;j++){
            if(Tabs(_elem[i][j] - e) < FLT_EPSILON){
                std::cout << "search_successfully"<<std::endl;
                std::cout<<"position:"<<"("<< (i+1) << "," << (j+1) << ")" <<std::endl;
                return true;
            }
        }
    }
    std::cout << "search_failed"<<std::endl;
    return false;
}
template<typename T>
bool Matrix<T>::search_row(int row,T const& e) const{
    for(int i = 0;i<_col;i++){
        if(Tabs(_elem[row - 1][i] - e) < FLT_EPSILON){
            std::cout << "search_successfully"<<std::endl;
            std::cout<<"position:"<<"("<< row << "," << (i+1) << ")" <<std::endl;
            return true;
        }
    }
    std::cout << "search_failed"<<std::endl;
    return false;
}
template<typename T>
bool Matrix<T>::search_col(int col,T const& e) const{
    for(int i = 0;i<_row;i++){
        if(Tabs(_elem[i][col - 1] - e) < FLT_EPSILON){
            std::cout << "search_successfully"<<std::endl;
            std::cout<<"position:"<<"("<< (i+1) << "," << col<< ")" <<std::endl;
            return true;
        }
    }
    std::cout << "search_failed"<<std::endl;
    return false;
}
template <typename T> template <typename VST>
void Matrix<T>::traverse(VST& visit) const{
    for(int i = 0;i<_row;i++){
        for(int j = 0;j<_col;j++){
            visit(_elem[i][j]);
        }
    }
}
template <typename T>
void Matrix<T>::traverse(){
    for(int i = 0;i<_row;i++){
        for(int j = 0;j<_col;j++){
            std::cout << _elem[i][j];
            std::cout << " " ;
        }
        std::cout << std::endl;
    }
}
template<typename T> 
Matrix<T> Matrix<T>::get_row(int row) const{
    Matrix<T> C(1,_col,0);
    for(int i = 0;i < _col;i++){
        C._elem[0][i] = _elem[row - 1][i];
    }
    return C;
}
template<typename T> 
Matrix<T> Matrix<T>::get_col(int col) const{
    Matrix<T> C(_row,1,0); //一个_row行1列的矩阵用来存放
    for(int i = 0;i < _row;i++){
        C._elem[i][0] = _elem[i][col-1];
    }
    return C;
}
template<typename T> 
Matrix<T> Matrix<T>::get_submatrix(int r_lo, int row, int c_lo, int col) const{
    if(r_lo <1||c_lo < 1) throw"ERROR";
    Matrix<T> C(row,col,0);
    for(int i = 0;i < row;i++){
        for(int j = 0;j< col;j++){
            C._elem[i][j] = _elem[r_lo+i-1][c_lo+j-1];
        }
    }
    return C;
}
template<typename T> 
Matrix<T>& Matrix<T>::insert_row(int row,T *p){//在第row行后面插入一行,思路是先创建一段临时内存
    _row++;
    T** oldElem = _elem;//申请一段临时的空间,保存原来的元素
    _elem = new T*[_row];
    for (int i = 0; i < _row; i++) {
        _elem[i] = new T[_col];
    }
    for(int i = 0;i< row;i++){
        for(int j = 0;j < _col;j++){
            _elem[i][j] = oldElem[i][j];
        }   
    }
    for(int i = 0;i< _col;i++){
        _elem[row][i] = p[i];
    }
    for(int i = row;i< _row - 1;i++){
        for(int j = 0;j < _col;j++){
            _elem[i+1][j] = oldElem[i][j];
        }   
    }
    delete[] oldElem;//记得释放临时空间
    return *this;
}
template<typename T> 
Matrix<T>& Matrix<T>::insert_col(int col,T *p){//在第col列后面插入一列
    _col++;
    T** oldElem = _elem;//申请一段临时的空间,保存原来的元素
    _elem = new T*[_row];
    for (int i = 0; i < _row; i++) {
        _elem[i] = new T[_col];
    }
    for(int i = 0;i< col;i++){
        for(int j = 0;j < _row;j++){
            _elem[j][i] = oldElem[j][i];
        }   
    }
    for(int i = 0;i< _row;i++){
        _elem[i][col] = p[i];
    }
    for(int i = col;i< _col - 1;i++){
        for(int j = 0;j < _row;j++){
            _elem[j][i+1] = oldElem[j][i];
        }   
    }
    delete[] oldElem;//释放原空间
    return *this;
}
template<typename T> 
Matrix<T>& Matrix<T>::remove_row(int row){
    _row--;
    for(int i = row - 1;i< _row;i++){
        for(int j = 0;j < _col;j++){
            _elem[i][j] = _elem[i+1][j];
        }   
    }
    delete[] _elem[_row]; //这里不会有问题,因为是删除了一行,是一个指针指向的,最后调用析构函数时_row改变,不会访问到已经被释放的这段内存
    return *this;
}
template<typename T> 
Matrix<T>& Matrix<T>::remove_col(int col){
    _col--;
    T** oldElem = _elem;//申请一段临时的空间,保存原来的元素
    _elem = new T*[_row];
    for (int i = 0; i < _row; i++) {
        _elem[i] = new T[_col];
    }
    for(int i = 0;i< col - 1;i++){
        for(int j = 0;j < _row;j++){
            _elem[j][i] = oldElem[j][i];
        }   
    }
    for(int i = col - 1;i< _col;i++){
        for(int j = 0;j < _row;j++){
            _elem[j][i] = oldElem[j][i+1];
        }   
    }
    // for(int i=0;i < _row;i++)
    //    delete &_elem[i][_row - 1];//这样问题很大,调用析构函数时依旧访问_elem,这样应该是释放已经被释放的内存块?emmmm
    delete[] oldElem;//释放原空间
    return *this;
}
template<typename T> 
Matrix<T> Matrix<T>::get_cofactor(int row,int col) const{
    if(_row != _col) throw"ERROR";
    Matrix<T> C = *this;
    C.remove_row(row);//通过把特定元素所在的行和列删去实现
    C.remove_col(col);
    return C;
}
template<typename T> 
T Matrix<T>::get_max() const{//返回矩阵中的最大元素,并且输出其所在的行数列数
    T row = 1,col = 1;
    T max = 0;
    for(int i = 0;i<_row;i++){
        for(int j = 0; j < _col;j++){
            if(_elem[i][j] > max){
                max = _elem[i][j];
                row = i + 1;
                col = j + 1;
            }
        }
    }
    std::cout<<"max_value:"<<max<<std::endl;
    std::cout<<"position:"<<"("<< row << "," << col << ")" <<std::endl;
    return max;
}
template<typename T> 
T Matrix<T>::get_min() const{//返回矩阵中的最小元素,并且输出其所在的行数列数
    T row = 1,col = 1;
    T min = _elem[0][0];
    for(int i = 0;i<_row;i++){
        for(int j = 0; j < _col;j++){
            if(_elem[i][j] < min){
                min = _elem[i][j];
                row = i + 1;
                col = j + 1;
            }
        }
    }
    std::cout<<"min_value:"<<min<<std::endl;
    std::cout<<"position:"<<"("<< row << "," << col << ")" <<std::endl;
    return min;
}
template<typename T> 
T Matrix<T>::get_average() const{//返回矩阵中元素的平均值,并且输出与之最接近的元素及所在的行数列数
    T sum = 0,avg = 0,row = 1,col = 1,csv= 0;
    for(int i = 0;i<_row;i++){
        for(int j = 0; j < _col;j++){
            sum += _elem[i][j];
        }
    }
    avg = sum/(_row*_col);
    T dis = Tabs(_elem[0][0] - avg);
    for(int i = 0;i<_row;i++){
        for(int j = 0; j < _col;j++){
            if(Tabs(_elem[i][j] - avg) < dis){
                dis = Tabs(_elem[i][j] - avg);
                csv = _elem[i][j];
                row = i + 1;
                col = j + 1;
            }
        }
    }
    std::cout<<"average_value:"<<avg<<std::endl;
    std::cout<<"closest_value:"<<csv<<std::endl;
    std::cout<<"position:"<<"("<< row << "," << col << ")" <<std::endl;
    return avg;
}
template<typename T>
Matrix<T> Matrix<T>::Transpose() const{
    Matrix<T> C(_col,_row,0);
    for(int i = 0;i<C._row;i++){
        for(int j = 0;j<C._col;j++){
            C._elem[i][j] = _elem[j][i];
        }
    } 
    return C;
}
template<typename T>
Matrix<T> Matrix<T>::Adjoint() const{
    Matrix<T> C(_row,_col,0);
    for(int i = 0;i<C._row;i++){
        for(int j = 0;j<C._col;j++){
            C._elem[i][j] = pow(-1,i + j)*(this->get_cofactor(i+1,j+1)).Det();
        }
    } 
    return C.Transpose();
}
template<typename T> 
Matrix<T> Matrix<T>::Flips() const{
    Matrix<T> C = *this;
    for(int i = 0;i<C._row;i++){
        for(int j = 0;j<C._col;j++){
            C._elem[i][j] = -C._elem[i][j];
        }
    } 
    return C;
}
template<typename T> 
T Matrix<T>::Det() const{
    if(_row != _col) throw"ERROR";
    if(_row < 2|| _col < 2) throw"ERROR"; //算行列式最少二阶
    T det = 0;
    if(_col < 3) {
        det = _elem[0][0]*_elem[1][1] - _elem[0][1]*_elem[1][0];
    }
    else{
        for(int i = 0;i< _col;i++){
            if(_elem[0][i] == 0) continue;//如果这一项为0,直接跳过递归环节节省运行时间
            //由这一点引起思考:如果含0元素多,则递归次数理论上减少,实现高效运算
            det += pow(-1,i)*_elem[0][i]*((this->get_cofactor(1,i+1)).Det());//细品这句,递归调用Det算
        }
    }
    return det;
}
template<typename T> 
Matrix<T> Matrix<T>::Inverse() const{
    T det = this->Det();
    if(_row != _col || det == 0) throw"ERROR";
    Matrix<T> C = this->Adjoint();
    for(int i = 0;i<C._row;i++){
        for(int j = 0;j<C._col;j++){
            C._elem[i][j] = C._elem[i][j] / det;
        }
    } 
    return C;
}
template<typename T> 
Matrix<T> Matrix<T>::operator+(Matrix<T> const&M) const{//矩阵的+操作
    if(M._row != _row || M._col != _col){  //参与运算的矩阵阶数不同
        throw "Order mismatch";
    }
    Matrix<T> C(_row,_col,0);
    for(int i = 0;i<_row;i++){
        for(int j = 0;j<_col;j++){
            C._elem[i][j] = _elem[i][j] + M._elem[i][j];
        }
    } 
    return C;
}
template<typename T> 
Matrix<T> Matrix<T>::operator-(Matrix<T> const&M) const{//矩阵的-操作
    Matrix<T> C = M.Flips();
    return (*this + C);//加法运算+矩阵元素取反
    //return (*this + M.Flips());  //不知道这样为什么会报错
}
template<typename T> 
Matrix<T> Matrix<T>::operator*(Matrix<T> const&M) const{//矩阵的*操作
    if(M._col != _row){  //M:m×p this:p×n CM:m×n
        throw "Order mismatch";
    }
    Matrix<T> C(_row,M._col,0);
        for(int i = 0;i<_row;i++){
            for(int j = 0;j<M._col;j++){
                for(int k = 0;k<_col;k++){
                    C._elem[i][j] += _elem[i][k]*M._elem[k][j];
                }
            }
        } 
    return C;
}
template<typename T> 
Matrix<T> Matrix<T>::operator/(Matrix<T> const&M) const{//矩阵的/操作
    Matrix<T> C = M.Inverse();
    return (*this*C);
}
template<typename T> 
Matrix<T> Matrix<T>::operator+(T m) const{//矩阵和标量的+操作
    Matrix<T> C = *this;
    for(int i = 0;i<_row;i++){
        for(int j = 0;j<_col;j++){
            C._elem[i][j] += m;
        }
    } 
    return C;
}
template<typename T> 
Matrix<T> Matrix<T>::operator-(T m) const{//矩阵和标量之间的-操作
    Matrix<T> C = *this;
    for(int i = 0;i<_row;i++){
        for(int j = 0;j<_col;j++){
            C._elem[i][j] -= m;
        }
    } 
    return C;
}
template<typename T> 
Matrix<T> Matrix<T>::operator*(T m) const{//矩阵和标量之间的*操作
    Matrix<T> C = *this;
    for(int i = 0;i<_row;i++){
        for(int j = 0;j<_col;j++){
            C._elem[i][j] *= m;
        }
    } 
    return C;
}
template<typename T> 
Matrix<T> Matrix<T>::operator/(T m) const{//矩阵和标量之间的/操作
    Matrix<T> C = *this;
    for(int i = 0;i<_row;i++){
        for(int j = 0;j<_col;j++){
            C._elem[i][j] /= m;
        }
    } 
    return C;
}

#endif

Visit.h

#ifndef VISIT_H
#define VISIT_H
template<typename T>class Cout{
public:
    void operator()(T a1){  //重载()运算符
        std::cout << a1 << std::endl;
    }
};
template<typename T>class Value{
public:
    void operator()(T &origon,T value){  //重载()运算符
        origon = value;
    }
};

#endif

main.cpp

/*
矩阵类实现
2018301898陈鹏宇
2020.3.5
注意所有关于行数列数的传参,都是按照取值范围为[1,n]设计的,即数据的_elem[0][0]为第一行第一列的元素
只有插入和删除操作真正改变了原数组的值,其余运算仅仅返回一个经拷贝的对象
*/
#include<iostream>
#include "Matrix.h"
#include "Visit.h"
#include "time.h"
using std::cout;
using std::endl;
int main(){
    double e = 3.0;
    double p[4] = {1,2,3,4};
    double q[5] = {1,2,3,4,5};
    Matrix<double> M(4,4);//自己在控制台输入矩阵数据
    Matrix<double> N(4,4,2);//所有元素初始化为2
    cout<<endl;
    cout<<"原矩阵M:"<<endl;
    M.traverse();//遍历并输出Matrix类对象M中的元素
    cout<<endl;
    cout<<"得到矩阵的一行:"<< endl;
    (M.get_row(2)).traverse();//得到第二行的所有元素并输出
    cout<<endl;
    cout<<"得到矩阵的一列:"<< endl;
    (M.get_col(2)).traverse();//得到第二列的所有元素并输出
    cout<<endl;
    cout<<"得到子矩阵:" << endl;
    (M.get_submatrix(2,3,3,2)).traverse();//返回子矩阵,第二行开始提取三行,第三列开始提取两列
    cout<<endl;
    cout<<"矩阵之间的加法运算:" << endl;
    (M+N).traverse();//重载运算符进行矩阵之间的加法运算
    cout<<endl;
    cout<<"矩阵之间的减法运算:" << endl;
    (M-N).traverse();//矩阵之间的减法运算
    cout<<endl;
    cout<<"矩阵之间的乘法运算:" << endl;
    (M*N).traverse();//矩阵之间的乘法运算
    cout<<endl;
    cout<<"矩阵之间的除法运算:" << endl;
    cout<<"注意!!!!如果N的行列式为0的话是不能求逆矩阵的!!!比如所有元素都相等的情况,还有输入连续元素的情况"<<endl;
    //int start = clock();
    (N/M).traverse();//矩阵之间的除法运算
    //int end = clock();
    //cout << end - start << endl;
    //其中还涉及了矩阵求余子式,求行列式的值,求转置矩阵,求伴随矩阵,求逆矩阵
    //注意!!!!如果N的行列式为0的话是不能求逆矩阵的!!!比如所有元素都相等的情况,还有输入连续元素的情况
    cout<<endl;
    cout<<"矩阵与标量之间的加法运算:" << endl;
    (M+e).traverse();//重载运算符进行矩阵与标量之间的加法运算
    cout<<endl;
    cout<<"矩阵与标量之间的减法运算:" << endl;
    (M-e).traverse();//矩阵与标量之间的减法运算
    cout<<endl;
    cout<<"矩阵与标量之间的乘法运算:" << endl;
    (M*e).traverse();//矩阵与标量之间的乘法运算
    cout<<endl;
    cout<<"矩阵与标量之间的除法运算:" << endl;
    (M/e).traverse();//矩阵与标量之间的除法运算
    cout<<endl;
    cout<<"返回矩阵中的最大元素,并且输出其所在的行数列数:" << endl;
    M.get_max();//返回矩阵中的最大元素,并且输出其所在的行数列数
    cout<<endl;
    cout<<"返回矩阵中的最小元素,并且输出其所在的行数列数:" << endl;
    M.get_min();//返回矩阵中的最小元素,并且输出其所在的行数列数
    cout<<endl;
    cout<<"返回矩阵中元素的平均值,并且输出与之最接近的元素及所在的行数列数:" << endl;
    M.get_average();//返回矩阵中元素的平均值,并且输出与之最接近的元素及所在的行数列数
    cout<<endl;
    cout<<"矩阵中插入一行:" << endl;
    (M.insert_col(3,p)).traverse();//矩阵第三行后面插入p指向的一维数组中的所有元素,多的元素舍去,缺的元素补0
    cout<<endl;
    cout<<"矩阵中插入一列:" << endl;
    (M.insert_row(2,q)).traverse();//矩阵第二列后面插入q指向的一维数组中的所有元素
    cout<<endl;
    cout<<"矩阵中删除一行:" << endl;
    (M.remove_row(4)).traverse();//删除矩阵的第四行
    cout<<endl;
    cout<<"矩阵中删除一列:" << endl;
    (M.remove_col(1)).traverse();//删除矩阵的第一列
    cout<<endl;
    cout<<"在矩阵中查找元素:" << endl;
    M.search(5);//在矩阵中查找元素5,若成功函数值为1,失败为0.
    cout<<endl;
    cout<<"在矩阵中某行查找元素:" << endl;
    M.search_row(2,4);//在矩阵中第2行查找元素4
    cout<<endl;
    cout<<"在矩阵中某列查找元素:" << endl;
    M.search_col(3,4);//在矩阵中第3列查找元素7
    cout << endl;
    return 0;
}
/*****测试元素,直接复制到控制台即可
1
0
2
1
3
2
5
0
7
3
2
0
2
3
1
0
***/

运行效果

在这里插入图片描述
 在这里插入图片描述
   在这里插入图片描述

易错整理:

1、模板类不可以将声明和定义分文件写。

参考:为什么C++编译器不能支持对模板的分离式编译

2、关于二维数组的动态创建、释放、访问和传参

创建和释放参考本文中Matrix类的构造和析构函数。

访问,追根到底是搞清楚二维数组的存储方式
假如有一个二维数组:

int a[3][4] = {{1, 3, 5, 7}, {9, 11, 13, 15}, {17, 19, 21, 23}};

其中,a 是二维数组名。a 数组包含 3 行,即 3 个行元素:a[0],a[1],a[2]。
每个行元素都可以看成含有 4 个元素的一维数组。而且 C 语言规定,a[0]、a[1]、a[2]分别是这三个一维数组的数组名。如下所示:
       在这里插入图片描述
因此,指向二维数组名的实际上是一个二重指针,即一个指向指针的指针。
访问方法:

a[i][j]  或者  *(*(a+i) + j)

关于第二个,第一个取值运算*表示得到a+i指向的那个指针,即第i行的首地址。再取值访问(i,j)

3、构造函数可以通过这样的方式定义:

Vector(int c = DEFAULT_CAPACITY,int s = 0 ,T v = 0){ //容量为c,规模为s,所有元素初始化v
        _elem = new T[_capacity = c];
        for (_size = 0; _size < s; _elem[_size++] = v);//s<=c   此刻向量的规模要比最大容量小
    }

这个是在类内定义的构造函数,注意到其有默认参数。如果定义对象时不传参,则默认参数被传入构造。但是这种默认参数的方法,只能用于类内定义,而不能类外定义。

另一种:

template<typename T> 
Matrix<T>::Matrix(int row, int col, T v) :_row(row),_col(col){ //构造的矩阵的行数和列数
    _elem = new T*[_row];
    for (int i = 0; i < _row; i++) {
        _elem[i] = new T[_col];
    } //二维数组动态分配内存的构造方法
    for(int i = 0;i < _row;i++){
        for(int j = 0;j < _col;j++){
            _elem[i][j] = v;
        }
    }    
}

这个构造函数冒号后面也是初始化列表,这种方式可以直接对成员变量进行初始化。

4、关于内存分配:

delete只能释放掉通过new获得的内存块,传给delete的是指向该内存块的指针。这个指针不可以被修改,如指向其他的内存,这样delete时会报错。
但是可以先人为释放掉这段内存后,再将这个指针指向其他内存块。注意不能尝试释放所指内存已经被释放的指针。

5、关于拷贝构造函数

对于普通类型的对象来说,它们之间的复制是很简单的,可以通过等号直接赋值。
而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。
拷贝构造函数往往适用于:
(1)当函数的参数为类的对象时
(2)函数的返回值是类的对象时

template<typename T> 
Matrix<T>::Matrix(const Matrix<T> &obj):_row(obj._row),_col(obj._col){//拷贝构造函数
    _elem = new T*[_row];
    for (int i = 0; i < _row; i++) {
        _elem[i] = new T[_col];
    }
    for(int i = 0;i < _row;i++){
        for(int j = 0;j < _col;j++){
            _elem[i][j] = obj._elem[i][j];//把元素复制过去
        }
    }  
}

这是一个函数的返回值是类的对象的例子,拷贝构造函数的形式常为:

Classname(const Classname &obj)

内部主要实现的是将传入的对象中的成员变量赋值给自己的成员变量,实现对象的构造过程。
调用方式一般为:

Classname M;//构造函数建立M
Classname N = Classname(M);//在N建立时通过拷贝构造函数将M的值都拷贝给N

6、引用作为函数的返回值

template<typename T> 
Matrix<T>& Matrix<T>::remove_row(int row){
    _row--;
    for(int i = row - 1;i< _row;i++){
        for(int j = 0;j < _col;j++){
            _elem[i][j] = _elem[i+1][j];
        }   
    }
    delete[] _elem[_row]; //这里不会有问题,因为是删除了一行,是一个指针指向的,最后调用析构函数时_row改变,不会访问到已经被释放的这段内存
    return *this;
}

1.引用作为函数的返回值时,必须在定义函数时在函数名前将&

2.用引用作函数的返回值的最大的好处是在内存中不产生返回值的副本

3、之前写代码时碰到一个这样的错误:
在这里插入图片描述
加上&后就不再报错,原因不明,可能是在析构时出现了问题。

发布了5 篇原创文章 · 获赞 5 · 访问量 359

猜你喜欢

转载自blog.csdn.net/gaiyi7788/article/details/104683556