由编写矩阵class想到的

2024-02-04 15:18
文章标签 编写 矩阵 class 想到

本文主要是介绍由编写矩阵class想到的,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

         我们今天线性代数刚好学到矩阵了,于是尝试将所学的编程知识加以实践,利用在高数上面。再加上C++如此强大的表达能力,写好了一个类之后就可以把它当做一个组件,甚至作为内置类型来用。

         当然,说起来容易做起来难。编程就是这样,萌生一个想法很容易,但是如果要把这个想法加以细化,再予以实现,需要的不仅仅是耐心,还有扎实的编程功底。笔者这个寒假看了一本叫做《Effective C++》的书。其实看之前我还是怀着将信将疑的态度的,既然是Effective那应该和我们没有太大的关系吧,反正那是以后的事?因为有牛人推荐去看一下这本书,所以我看下去了,一探究竟为何推荐这本书。现在看来,笔者认为,《Effective C++》确实是一本好书的。其一,养成良好的编程习惯是要从学生开始的;同样,我们应该要养成高效的编程习惯,有时一个小小的细节可能会对性能产生绝对的影响(比如对象的函数传递不用const引用类型)。其二,我们在学习如何高效率编程的时候其实会对语言实现的原理进行深入的了解。所以,这是一本好书,值得一读的。

顺便一提的是,一开始看的是中文版电子书,不过后面我在网上买了一本评注版的,也就是英文版,看得云里雾里,一知半解。我以前对自己的英文水平有着过分的自信,可惜面对英文版的书,还是原形毕露了。尽管也许每个词都看得懂,句子也勉强通过,文意老是捉摸不透。所以说我现在明白了,除非是有特殊的需要,尽量选择中文版的书看,不要因为图新鲜或为了证明自己的能力而去买英文版的,真的,中文版可能翻译得不好,但是我们读者可以明白得一样好。

好了,说远了,下面是我这个class的设计。

class Matrix{

private:

    int **Mtx;

    int cols;

    int rows;

    static void intMult(Matrix& mtx, intLamda);

public:

    friend ostream&operator<<(ostream& out, const Matrix& mt);

    friend istream&operator>>(istream& in, Matrix& mt);

    friend const Matrix operator*(int lamda,const Matrix& rhs);

 

    explicit Matrix(int i=0, int j=0);

    Matrix(const Matrix& rhs); //Copy fx

         void operator=(const Matrix& rhs);//copy assignment

    ~Matrix();

 

    const Matrix operator+(const Matrix&rhs) const;

    const Matrix operator-(const Matrix& rhs)const;

    const Matrix operator*(const Matrix&rhs) const;

    const Matrix operator*(int lamda) const;

 

    const int getElem(int row, int col) const;

    const int getRow() const {return rows;}

    const int getCol() const {return cols;}

    const int getMtx(int i, int j) const{return Mtx[i][j];}

};

一开始考虑该如何存放矩阵,想着简单,但却着实烦扰了我半天。我可以选择复合的vector,但是因为是练习嘛,我打算挑战自己,建立一个二位数组。考虑到需要动态存储,我将二维数组的指针存放在int **Mtx中。大家都懂得,什么程序,一旦扯上指针就是处于灾难的边缘了。更何况指针的指针。Mtx指向一组int*,是个指针的数组。而每个int*又指向一组int。于是一个二维数组就这么诞生了(想象一下一个二维表,表头指向许多行,而每一行又指向了该行的所有元素)。所以,我令Mtx指向的一组int*作为行,而int*指向的一组int作为这一行的所有列。那么,Mtx[i][j]是第i行第j列呢,还是反着说呢?我一直都没弄清楚。经过试验可以确定从左向右的原则任然成立,也就是说是i行j列。大家也可以试一试,比较下(Mtx[i])[j](i行j列)和Mtx[i][j]的效果就可以了。看这个代码:

    Ptr[1][2]=10;

    cout << Ptr[1][2] << endl;

    cout << (Ptr[1])[2];

假设Ptr是经过分配并已初始化的int**,上面的结果两个都是10,也就是说从左向右的顺序成立。

初始化代码如下:

    Mtx=new int*[rows];

    for(int i=0;i<rows;i++){

        Mtx[i]=new int[cols];

        for(int j=0;j<cols;j++)Mtx[i][j]=rhs.Mtx[i][j];

    }

         存储问题解决了,一切就可以循序渐进了。

         Explicit的构造函数是什么呢?它是为了阻止编译器在幕后进行隐式类型转换。比如说令int a=1.22f,这时候就涉及到隐式类型转换了,编译器在幕后将(float)1.22转换为了(int)1,并且赋值给a。而显示转换比如说static_cast等,在此不赘述,可以参考reference。隐式转换在有些时候会给我们带来麻烦,这是Effective C++里面提到的。于是,一开始,我遵守了约定,将Matrix::Matrix(const Matrix&)也声明为explicit,问题就出现了。比如,设在函数里有一个Matrix M,如果我要return M的话,编译器却不干了:Error: no matching function for call to'Matrix::Matrix(Matrix&)'。我猜想,return需要创建一个对象保存结果并传递,而不是直接将M的内存区域移交给函数调用者。这就涉及到一个隐式构造函数(编译器自动创建了一个临时对象),而这个行为是被explicit所禁止的。将copy构造的explicit去掉就可以通过了。所以,可以得出,对于一个copy构造函数修饰explicit是坏主意,除非你认为这确实有必要。

         笔者还遇上了一个问题,在刚才也提到过传递const引用会对性能有很大的提升,但是,这不仅仅是性能,有的时候如果忘记给引用加const结果会很糟糕。比如说如果把构造函数写为Matrix::Matrix(Matrix&),看似没什么问题,但是一旦要构造MatrixM(M1+M2);呢?编译器又不干了,因为M1+M2的结果是const的。那如果我把Matrix::operator+()的返回值修改为非const的呢?会导致一些问题,比如M1+M2=M3;这类无效的语句却会通过编译。这是不被提倡的。

         这些做完之后,对照我们线性代数的书,根据矩阵的性质一条条地编写运算律。当然,这只是一小部分,我还会在学习线性代数的同时对它加以完善。做一个Matrix类是件小事,可能标准库还带了,但是更重要的是实践。通过实践可以让我们注意到平时看书时不被注意到的一些细节。编程是要求思维严密过细的。我感觉,C++继承了C语言的一些特性,保留了指针,使得底层高效的东西得以实现。又有灵活的类型系统,让STL、TR1这些杰作方便了我们编程的过程。C++确实是一个很优秀的语言,如果我们能掌握它,它就能很好地为我们服务。

博文

2012/3/3 0:43 于宿舍

(转载请保留)

这篇关于由编写矩阵class想到的的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/677933

相关文章

BD错误集锦8——在集成Spring MVC + MyBtis编写mapper文件时需要注意格式 You have an error in your SQL syntax

报错的文件 <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.yuan.dao.YuanUserDao"><!

如何利用echarts编写立体的柱状图表

1、引入 import * as echarts from 'echarts' 2、创建图标容器 3、调用渲染 <template><div ref="eachrtsBox" style="width: 200px;height: 200px;"></div></template><script>import * as echarts from 'echarts'export d

ssh在本地虚拟机中的应用——解决虚拟机中编写和阅读代码不方便问题的一个小技巧

虚拟机中编程小技巧分享——ssh的使用 事情的起因是这样的:前几天一位工程师过来我这边,他看到我在主机和虚拟机运行了两个vscode环境,不经意间提了句:“这么艰苦的环境写代码啊”。 后来我一想:确实。 我长时间以来都是直接在虚拟机里写的代码,但是毕竟是虚拟机嘛,有时候编辑器没那么流畅,在文件比较多的时候跳转很麻烦,容易卡住。因此,我当晚简单思考了一下,想到了一个可行的解决方法——即用ssh

简单 使用 的makefile编写 框架

1、指定编译器,如海思平台:CROSS_COMPILE=arm-hisiv100nptl-linux-; 2、指定编译工具:GCC=$(CROSS_COMPILE)gcc   CC=$(CROSS_COMPILE)g++; 3、使用 export 导出 子makefile 要用的变量; 4、定义变量的形式  指定 工程源文件 需要使用到的 “宏”,在后面的 LDFLAGS 里面使用 -D将其

Class 对象在执行引擎中的初始化过程

一个 class 文件被加载到内存中需要经过 3 大步:装载、链接、初始化。 装载 装载是指 Java 虚拟机查找 .class 文件并生成字节流,然后根据字节流创建 java.lang.Class 对象的过程。 链接 链接过程分为 3 步:验证、准备、解析。 验证: 初始化 这是 class 加载的最后一步,这一阶段是执行类构造器方法的过程,并真正初始化类变量。 1.文件格式检验:检

(转)Sublime Text 2 (Emmet):HTML/CSS代码快速编写神器

Emmet的前身是大名鼎鼎的Zen coding,如果你从事Web前端开发的话,对该插件一定不会陌生。它使用仿CSS选择器的语法来生成代码,大大提高了HTML/CSS代码编写的速度,比如下面的演示:   Zen coding下的编码演示   去年年底,该插件已经改名为Emmet。但Emmet不只改名,还带来了一些新特性。本文就来直观地演示给你。 一、快速编写HTML代码 1.

编程精粹—— Microsoft 编写优质无错 C 程序秘诀 07:编码中的假象

这是一本老书,作者 Steve Maguire 在微软工作期间写了这本书,英文版于 1993 年发布。2013 年推出了 20 周年纪念第二版。我们看到的标题是中译版名字,英文版的名字是《Writing Clean Code ─── Microsoft’s Techniques for Developing》,这本书主要讨论如何编写健壮、高质量的代码。作者在书中分享了许多实际编程的技巧和经验,旨在

推荐算法之矩阵分解实例

矩阵分解的数据利用的上篇文章的数据,协同过滤 用到的知识 python的surprise k折交叉验证 SVD SVDpp NMF 算法与结果可视化 # 可以使用上面提到的各种推荐系统算法from surprise import SVD,SVDpp,NMFfrom surprise import Datasetfrom surprise import print_perf

Linux内核开发-编写一个内核模块

0.前言 上一章(点击返回上一章)已经完成了将ubuntu原始内核替换成了自己编好的内核。本章开始编写一个内核模块。 1.内核模块 1.1 什么是内核模块 Linux内核模块可独立于内核之外进行编译,可以在内核运行时动态加载、卸载。内核模块以.ko为后缀。 1.2 操作内核模块常用的指令 # 查看当前正在运行的模块lsmod#插入一个模块insmod module_name# 卸载

江协科技51单片机学习- p16 矩阵键盘

🚀write in front🚀   🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​  💬本系列哔哩哔哩江科大51单片机的视频为主以及自己的总结梳理📚  前言: 本文是根据哔哩哔哩网站上“江协科技51单片机”视频的学习笔记,在这里会记录下江协科技51单片机开发板的配套视频教程所作的实验和学习