由编写矩阵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

相关文章

使用Java编写一个文件批量重命名工具

《使用Java编写一个文件批量重命名工具》这篇文章主要为大家详细介绍了如何使用Java编写一个文件批量重命名工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录背景处理1. 文件夹检查与遍历2. 批量重命名3. 输出配置代码片段完整代码背景在开发移动应用时,UI设计通常会提供不

提示:Decompiled.class file,bytecode version如何解决

《提示:Decompiled.classfile,bytecodeversion如何解决》在处理Decompiled.classfile和bytecodeversion问题时,通过修改Maven配... 目录问题原因总结问题1、提示:Decompiled .class file,China编程 bytecode

hdu 4565 推倒公式+矩阵快速幂

题意 求下式的值: Sn=⌈ (a+b√)n⌉%m S_n = \lceil\ (a + \sqrt{b}) ^ n \rceil\% m 其中: 0<a,m<215 0< a, m < 2^{15} 0<b,n<231 0 < b, n < 2^{31} (a−1)2<b<a2 (a-1)^2< b < a^2 解析 令: An=(a+b√)n A_n = (a +

如何编写Linux PCIe设备驱动器 之二

如何编写Linux PCIe设备驱动器 之二 功能(capability)集功能(capability)APIs通过pci_bus_read_config完成功能存取功能APIs参数pos常量值PCI功能结构 PCI功能IDMSI功能电源功率管理功能 功能(capability)集 功能(capability)APIs int pcie_capability_read_wo

hdu 6198 dfs枚举找规律+矩阵乘法

number number number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description We define a sequence  F : ⋅   F0=0,F1=1 ; ⋅   Fn=Fn

列举你能想到的UNIX信号,并说明信号用途

信号是一种软中断,是一种处理异步事件的方法。一般来说,操作系统都支持许多信号。尤其是UNIX,比较重要应用程序一般都会处理信号。 UNIX定义了许多信号,比如SIGINT表示中断字符信号,也就是Ctrl+C的信号,SIGBUS表示硬件故障的信号;SIGCHLD表示子进程状态改变信号;SIGKILL表示终止程序运行的信号,等等。信号量编程是UNIX下非常重要的一种技术。 Unix信号量也可以

Wondows dos下怎么编写bat批处理文件

最近搞php,在运行时,以Nginx+php-cgi.exe方式运行Wordpress项目 打开dos,先cd到php-cgi.exe文件当前目录下执行启动命令:php-cgi.exe -b 127.0.0.1:9001再打开一个dos,再cd到nginx.exe文件当前目录下执行启动命令:start nginx 大概过程要经过这些步骤,觉得很麻烦,就学下怎么编写一个bat文件,以双击运行代替

类型信息:反射-Class

在说反射前提一个概念:RTTI(在运行时,识别一个对象的类型) public class Shapes {public static void main(String[] args) {List<Shape> shapes = Arrays.asList(new Circle(), new Square(), new Triangle());for (Shape shape : shapes

react笔记 8-17 属性绑定 class绑定 引入图片 循环遍历

1、绑定属性 constructor(){super()this.state={name:"张三",title:'我是一个title'}}render() {return (<div><div>aaaaaaa{this.state.name}<div title={this.state.title}>我是一个title</div></div></div>)} 绑定属性直接使用花括号{}   注

用Python编写倒计时程序:详细教程

目录 引言 环境准备 基本概念 代码实现 步骤一:导入必要的库 步骤二:获取用户输入 步骤三:实现倒计时逻辑 步骤四:整合代码 运行程序 高级功能 扩展功能示例:支持分钟和小时输入 扩展功能示例:图形用户界面 (GUI) 总结 引言 倒计时程序是一个非常常见的小工具,广泛用于各种应用场景中,例如考试时间提醒、烹饪计时器、会议倒计时等。Python 作为一种