uda 4.C++面向对象编程

Python vs C++ 对比课

 

在本课中,你将学习如何用 C++ 编写类。像之前的课程同样,你须要比较 Python 的编程方式和 C++ 中编程方式的不一样。python

咱们直接看例子。下面是一个名为 “Gaussian” 的 Python 类代码。该类包含两个类变量:平均值 “mu”,以及方差 “sigma2”。react

你学太高斯分布,并在以前的纳米学位中看过这些方程。ios

类包括三个函数:c++

  1. evaluate,它表示几率密度函数 。
  2. multiply,它将两个高斯分布相乘。
  3. add,它将两个高斯分布相加。
 

Gaussian 类的 Python 代码

class Gaussian():

    def __init__(self, mean, variance):
        self.mu = mean
        self.sigma2= variance

    def evaluate(self, x):
        coefficient = 1.0 / sqrt(2.0 * pi *self.sigma2)
        exponential = exp(-0.5 * (x-self.mu) ** 2 / self.sigma2)
        return coefficient * exponential

    def multiply(self, other):
        # 计算新均值
        denominator =self.sigma2+other.sigma2
        numerator = self.mu * other.sigma2 + other.mu * self.sigma2
        new_mu = numerator / denominator

        # 计算新方差
        new_var =1.0/ ( (1.0/self.sigma2) + (1.0/other.sigma2) )

        # 生成新的高斯分布
        return Gaussian(new_mu, new_var)

    def add(self, other):
        new_mu = self.mu + other.mu
        new_sigma2 =self.sigma2+other.sigma2

        return Gaussian(new_mu, new_sigma2)

例:C++ 类

 

如今,咱们来看看 C++ 中的的一个等价类。和你看到的其余例子同样,C++ 代码更长,而且有 Python 版本没有的方面。编程

例如,你会注意到,在 C++ 类中,全部的变量及其全部的函数都须要在编写实现以前先声明。类还有一部分标记为private,另外一部分标记为public。此外,C++ 类还包括诸如setMusetSigma2getMugetSigma2等额外的函数。后端

你将在本课中了解全部这些差别。如今,请仔细阅读代码,看看你可否理解 set 函数和 get 函数的功能。markdown

# include <math.h>

class Gaussian
{
    private:
        float mu, sigma2;

    public:

        // constructor functions
        Gaussian ();
        Gaussian (float, float);

        // change value of average and standard deviation 
        void setMu(float);
        void setSigma2(float);

        //输出平均值和标准差的值
        float getMu();
        float getSigma2();

        //待评估函数
        float evaluate (float);
        Gaussian multiply (Gaussian);
        Gaussian add (Gaussian);
};

Gaussian::Gaussian() {
    mu = 0;
    sigma2 = 1;    
}

Gaussian::Gaussian (float average, float sigma) {
    mu = average;
    sigma2 = sigma;
}

void Gaussian::setMu (float average) {
    mu = average;
}

void Gaussian::setSigma2 (float sigma) {
    sigma2 = sigma;
}


float Gaussian::getMu () {
    return mu;
}

float Gaussian::getSigma2() {
    return sigma2;
}

float Gaussian::evaluate(float x) {
    float coefficient;
    float exponential;

    coefficient = 1.0 / sqrt (2.0 * M_PI * sigma2);
    exponential = exp ( pow (-0.5 * (x - mu), 2) / sigma2 );
    return coefficient * exponential;
}

Gaussian Gaussian::multiply(Gaussian other) {
    float denominator;
    float numerator;
    float new_mu;
    float new_var;

    denominator = sigma2 + other.getSigma2();
    numerator = mu * other.getSigma2() + other.getMu() * sigma2;
    new_mu = numerator / denominator;

    new_var = 1.0 / ( (1.0 / sigma2) + (1.0 / other.sigma2) );

    return Gaussian(new_mu, new_var);
}

Gaussian Gaussian::add(Gaussian other) {

    float new_mu;
    float new_sigma2;

    new_mu = mu + other.getMu();
    new_sigma2 = sigma2 + other.getSigma2();

    return Gaussian(new_mu, new_sigma2);
}

在程序中使用类

在深刻了解如何编写 C++ 类的细节以前,首先要了解如何在 main.cpp 程序中使用类。在处理大项目时,你可能须要使用一个类,而实际上并不负责实施该类。函数

下面是一个使用 Gaussian 类的 main.cpp 文件。学习

首先,你的 main.cpp 文件须要在文件的顶部声明全部的变量和函数。而后,main() 函数须要有权访问该类,并可使用该类的方法:ui

# include <iostream>

//声明类
class Gaussian
{
    private:
        float mu, sigma2;

    public:

        //构造函数
        Gaussian ();
        Gaussian (float, float);

        //改变均差和标准误差值 
        void setMu(float);
        void setSigma2(float);

        //输出均差和标准误差值
        float getMu();
        float getSigma2();

        //待评估函数 
        float evaluate (float);
        Gaussian mul (Gaussian);
        Gaussian add (Gaussian);
};

int main ()
{

    Gaussian mygaussian(30.0,20.0);
    Gaussian othergaussian(10.0,30.0);

    std::cout << "average " << mygaussian.getMu() << std::endl;
    std::cout << "evaluation " << mygaussian.evaluate(15.0) << std::endl;

    std::cout << "mul results sigma " << mygaussian.mul(othergaussian).getSigma2() << std::endl;
    std::cout << "mul results average " << mygaussian.mul(othergaussian).getMu() << std::endl;

    std::cout << "add results sigma " << mygaussian.add(othergaussian).getSigma2() << std::endl;
    std::cout << "add results average " << mygaussian.add(othergaussian).getMu() << std::endl;

    return 0;
}

接下来,咱们学习类的编程步骤。

对象实例化

首先,你须要在程序的顶部声明该类。而后,在 main 函数内部,你能够实例化对象:

Gaussian mygaussian(30.0,20.0);
Gaussian othergaussian(10.0,30.0);

第一个对象叫作 mygaussian,平均值为 30,方差为 20。第二个对象叫作 othergaussian,平均值为 10,方差为 30。

使用对象方法

而后,你能够经过如下代码使用对象方法:

mygaussian.getMu()

它能够输出 mygaussian 对象内的平均值。

另外一个例子:

mygaussian.add(othergaussian)

它能够把 mygaussian 和 othergaussian 相加。

 

下面是在这个代码中使用的全部文件,方便你观察 main.cpp 和 gaussian.cpp 之间的关系

这个程序首先经过如下命令被编译,但你在后端看不到:

g++ main.cpp gaussian.cpp

#include <math.h>       /* sqrt, exp */

// class declaration
class Gaussian
{
    private:
        float mu, sigma2;

    public:
        
        // constructor functions
        Gaussian ();
        Gaussian (float, float);

        // change value of average and standard deviation 
        void setMu(float);
        void setSigma2(float);

        // output value of average and standard deviation
        float getMu();
        float getSigma2();

        // functions to evaluate 
        float evaluate (float);
        Gaussian mul (Gaussian);
        Gaussian add (Gaussian);
};


Gaussian::Gaussian() {
    mu = 0;
    sigma2 = 1;    
}

Gaussian::Gaussian (float average, float sigma) {
    mu = average;
    sigma2 = sigma;
}

void Gaussian::setMu (float average) {
    mu = average;
}

void Gaussian::setSigma2 (float sigma) {
    sigma2 = sigma;
}


float Gaussian::getMu () {
    return mu;
}

float Gaussian::getSigma2() {
    return sigma2;
}

float Gaussian::evaluate(float x) {
    float coefficient;
    float exponential;

    coefficient = 1.0 / sqrt (2.0 * M_PI * sigma2);
    exponential = exp ( pow (-0.5 * (x - mu), 2) / sigma2 );
    return coefficient * exponential;
}

Gaussian Gaussian::mul(Gaussian other) {
    float denominator;
    float numerator;
    float new_mu;
    float new_var;

    denominator = sigma2 + other.getSigma2();
    numerator = mu * other.getSigma2() + other.getMu() * sigma2;
    new_mu = numerator / denominator;

    new_var = 1.0 / ( (1.0 / sigma2) + (1.0 / other.sigma2) );

    return Gaussian(new_mu, new_var);
}

Gaussian Gaussian::add(Gaussian other) {

    float new_mu;
    float new_sigma2;

    new_mu = mu + other.getMu();
    new_sigma2 = sigma2 + other.getSigma2();

    return Gaussian(new_mu, new_sigma2);
}

类的剖析

开始编写你本身的 C++ 类以前,咱们再看一下 Gaussian.cpp 文件中的 Gaussian 类代码。咱们把类按部分分解。

gaussian.cpp 文件有如下几部分:

  • 类声明
  • 构造函数
  • 方法定义

首先,咱们看看本课程前一部分的整个 gaussian.cpp 代码:

# include <math.h>

class Gaussian
{
    private:
        float mu, sigma2;

    public:

        //构造函数
        Gaussian ();
        Gaussian (float, float);

        //改变均差和标准误差的值 
        void setMu(float);
        void setSigma2(float);

        //输出均差和标准误差的值
        float getMu();
        float getSigma2();

        //待评估函数 
        float evaluate (float);
        Gaussian multiply (Gaussian);
        Gaussian add (Gaussian);
};

Gaussian::Gaussian() {
    mu = 0;
    sigma2=1;    
}

Gaussian::Gaussian (float average, float sigma) {
    mu = average;
    sigma2= sigma;
}

void Gaussian::setMu (float average) {
    mu = average;
}

void Gaussian::setSigma2 (float sigma) {
    sigma2= sigma;
}


float Gaussian::getMu () {
    return mu;
}

float Gaussian::getSigma2() {
    returnsigma2;
}

float Gaussian::evaluate(float x) {
    float coefficient;
    float exponential;

    coefficient = 1.0 / sqrt (2.0 * M_PI * sigma2);
    exponential = exp ( pow (-0.5 * (x - mu), 2) / sigma2 );
    return coefficient * exponential;
}

Gaussian Gaussian::multiply(Gaussian other) {
    float denominator;
    float numerator;
    float new_mu;
    float new_var;

    denominator = sigma2 + other.getSigma2();
    numerator = mu * other.getSigma2() + other.getMu() * sigma2;
    new_mu = numerator / denominator;

    new_var =1.0/ ( (1.0/sigma2) + (1.0/other.sigma2) );

    return Gaussian(new_mu, new_var);
}

Gaussian Gaussian::add(Gaussian other) {

    float new_mu;
    float new_sigma2;

    new_mu = mu + other.getMu();
    new_sigma2 = sigma2 + other.getSigma2();

    return Gaussian(new_mu, new_sigma2);
}

在文件的顶部,你能够放置任何 include 语句以及类定义。在本例中,include 语句容许 Class 访问标准库中的数学文件。

# include <math.h> 
 

类声明

类声明在 include 语句以后。

类声明与你已经看到的变量和函数声明相似。你须要声明全部的类变量名称、类函数名称以及它们的类型:

class Gaussian
{
    private:
        float mu, sigma2;

    public:

        //构造函数
        Gaussian ();
        Gaussian (float, float);

        //改变均差和标准误差的值 
        void setMu(float);
        void setSigma2(float);

        //输出均差和标准误差的值
        float getMu();
        float getSigma2();

        //待评估函数 
        float evaluate (float);
        Gaussian multiply (Gaussian);
        Gaussian add (Gaussian);
};

请注意,每一个类的函数和变量都须要声明。全部类方法均可以使用 mu 和 sign2 这两个浮点变量;可是,一些类的函数实际上有本身的变量。一个例子是 evaluate 函数。若是你看一下 evaluate 函数的实现,你会看到这个函数有本身的变量:

float coefficient; float exponential; 

这两个变量不是类变量;coefficient 和 exponential 只能用于 evaluate 函数。

 

你可能已经注意到,其中一些声明在标为“private”的部分,其余声明则在标为“public”的部分。理解 private 和 public 之间的区是本课的目标之一。

 

构造函数

 

接下来是构造函数的定义。当你真正使用你的类来实例化一个对象时,这些函数会被调用。Python 有一个功能相同的语法 __init__

def __init__(self, variable1, variable2, ..., variablen): 

第一个构造函数用于在不指定平均值和方差的状况下实例化一个对象:

Gaussian::Gaussian() {
    mu = 0; sigma2=1; } 

另外一个构造函数指定在你肯定平均值和方差时要执行的操做:

Gaussian::Gaussian (float average, float sigma) { mu = average; sigma2= sigma; } 
 

方法

 

其他代码包含你的类中全部的函数的定义,也称为方法。

get 和 set 函数专门用于获取变量或更改私有变量的值。咱们会在本课后面部分详细讨论这个问题。

 

void Gaussian::setMu (float average) {
    mu = average;
}

void Gaussian::setSigma2 (float sigma) {
    sigma2= sigma;
}

float Gaussian::getMu () {
    return mu;
}

float Gaussian::getSigma2() {
    returnsigma2;
}

其他的函数 (evaluate、multiply、add) 和 Python 的类中的函数是同样的。

float Gaussian::evaluate(float x) {
    float coefficient;
    float exponential;

    coefficient = 1.0 / sqrt (2.0 * M_PI * sigma2);
    exponential = exp ( pow (-0.5 * (x - mu), 2) / sigma2 );
    return coefficient * exponential;
}

Gaussian Gaussian::multiply(Gaussian other) {
    float denominator;
    float numerator;
    float new_mu;
    float new_var;

    denominator = sigma2 + other.getSigma2();
    numerator = mu * other.getSigma2() + other.getMu() * sigma2;
    new_mu = numerator / denominator;

    new_var =1.0/ ( (1.0/sigma2) + (1.0/other.sigma2) );

    return Gaussian(new_mu, new_var);
}

Gaussian Gaussian::add(Gaussian other) {

    float new_mu;
    float new_sigma2;

    new_mu = mu + other.getMu();
    new_sigma2 = sigma2 + other.getSigma2();

    return Gaussian(new_mu, new_sigma2);
}

头文件

在前面的例子中,你看到了如何将一个类分红一个独立于 main.cpp 的文件(gaussian.cpp)。可是,主程序文件和 gaussian 类文件都须要在代码顶部进行彻底相同的类声明:

//类声明
class Gaussian
{
    private:
        float mu, sigma2;

    public:

        //构造函数
        Gaussian ();
        Gaussian (float, float);

        //改变均差和标准误差的值 
        void setMu(float);
        void setSigma2(float);

        //输出均差和标准误差的值
        float getMu();
        float getSigma2();

        //待评估函数 
        float evaluate (float);
        Gaussian mul (Gaussian);
        Gaussian add (Gaussian);
};

不须要写两次声明,只须要将声明写入头文件便可。而后,你能够用一行代码包含整个声明:

#include <iostream>
#include "gaussian.h"

int main ()
{

    Gaussian mygaussian(30.0,20.0);
    Gaussian othergaussian(10.0,30.0);
    
    std::cout << "average " << mygaussian.getMu() << std::endl;
    std::cout << "evaluation " << mygaussian.evaluate(15.0) << std::endl;

    std::cout << "mul results sigma " << mygaussian.mul(othergaussian).getSigma2() << std::endl;
    std::cout << "mul results average " << mygaussian.mul(othergaussian).getMu() << std::endl;

    std::cout << "add results sigma " << mygaussian.add(othergaussian).getSigma2() << std::endl;
    std::cout << "add results average " << mygaussian.add(othergaussian).getMu() << std::endl;

    return 0;
}
#include <math.h>       /* sqrt, exp */
#include "gaussian.h"

Gaussian::Gaussian() {
    mu = 0;
    sigma2 = 1;    
}

Gaussian::Gaussian (float average, float sigma) {
    mu = average;
    sigma2 = sigma;
}

void Gaussian::setMu (float average) {
    mu = average;
}

void Gaussian::setSigma2 (float sigma) {
    sigma2 = sigma;
}


float Gaussian::getMu () {
    return mu;
}

float Gaussian::getSigma2() {
    return sigma2;
}

float Gaussian::evaluate(float x) {
    float coefficient;
    float exponential;

    coefficient = 1.0 / sqrt (2.0 * M_PI * sigma2);
    exponential = exp ( pow (-0.5 * (x - mu), 2) / sigma2 );
    return coefficient * exponential;
}

Gaussian Gaussian::mul(Gaussian other) {
    float denominator;
    float numerator;
    float new_mu;
    float new_var;

    denominator = sigma2 + other.getSigma2();
    numerator = mu * other.getSigma2() + other.getMu() * sigma2;
    new_mu = numerator / denominator;

    new_var = 1.0 / ( (1.0 / sigma2) + (1.0 / other.sigma2) );

    return Gaussian(new_mu, new_var);
}

Gaussian Gaussian::add(Gaussian other) {

    float new_mu;
    float new_sigma2;

    new_mu = mu + other.getMu();
    new_sigma2 = sigma2 + other.getSigma2();

    return Gaussian(new_mu, new_sigma2);
}
class Gaussian
{
    private:
        float mu, sigma2;

    public:
        
        // constructor functions
        Gaussian ();
        Gaussian (float, float);

        // change value of average and standard deviation 
        void setMu(float);
        void setSigma2(float);

        // output value of average and standard deviation
        float getMu();
        float getSigma2();

        // functions to evaluate 
        float evaluate (float);
        Gaussian mul (Gaussian);
        Gaussian add (Gaussian);
};

类变量

在本课接下来的部分,你将实现一个矩阵类,就像你在 Python 面向对象编程课程中所作的同样。

如今,咱们假定你已经熟悉了基本的矩阵运算。因此本课的重点是练习编写 C++ 类。

你的第一个任务是在 Matrix 类中声明变量。下面是声明 C++ 类的通常语法,供参考:

class Classname { private: declare private variables; declare private functions; public: declare public variables; declare public functions; }; 

实际声明变量的代码与其余 C++ 变量声明相同:

datatype variablename;

Matrix 类有三个私有变量:

  • grid - 保存矩阵值de 2D浮点向量
  • rows - 矩阵的行数
  • columns - 矩阵的列数

行和列变量应该声明为 size_type。size_type 变量保存向量的大小。size_type 声明以下所示:

std::vector<int>::size_type variablename; 
#include <iostream>
#include <vector>
#include "matrix.h"

int main () {
    
    // TODO: Nothing to do here
    
    return 0;
}
include <vector>
using namespace std;
// Header file for the Matrix class

/* 
**  TODO:
**    Declare the following private variables:
**      a 2D float vector variable called grid
**      a vector size_type variable called rows
**      a vector size_type variable called cols
*/

class Matrix 
{
    
    private: vector< vector<float> >grid;
    private: vector<int> rows;
    private: vector<int>cols;
    
    
    
};

类函数

要在 Matrix 类中编写函数,首先须要声明这些函数。对于 Matrix 类,你能够将这些函数看做属于三个独立的类别:

  • 构造函数
  • set 和 get 函数
  • Matrix 功能函数

声明这些函数的方法和前一课中声明函数同样。不一样的是,如今你必须决定某个函数是私有的、受保护的仍是公共的。函数声明在类声明内部。

你须要在 matrix.cpp 中定义你的函数。但首先,让咱们简要地谈一下每种类型的函数。构造函数用于初始化对象。Python 使用def __init__语法实现这一功能。C++ 语法有点不一样,你将在本课的下一部分中了解这些差别。

set 和 get 取函数专门用于访问和赋值给私有变量。由于一个对象不能直接访问私有变量,set 和 get 函数提供了间接访问功能。set 和 get 函数的语法和其余 C++ 函数相同。使用 set 和 get 是面向对象编程的惯例,而不是特定的 C++ 语法。

最后,还有一些由矩阵功能组成的函数,如打印矩阵、矩阵相加、矩阵乘法等等。在练习中,你会执行这些函数。

下面,咱们进入到下一部分的练习,学习如何声明和定义 Matrix 构造函数。

 

Set 和 Get 函数声明

Set 和 Get 函数容许你的对象访问私有变量。对象不能直接访问私有变量,因此须要使用 set 和 get 函数。本课前面的 Gaussian 对象展现了具体实现方法。

如下是 set 和 get 函数的声明:

class Gaussian { private: ... public: ... void setMu(float); void setSigma2(float); float getMu(); float getSigma2(); .... }; 

set 函数改变一个变量的值,而 get 函数则返回一个变量的值。你会注意到,set 和 get 函数的语法与全部常规函数都是同样的。实际上,set 和 get 是约定,而不是 C++ 特有的。传统上,咱们将这些函数命名为 getVariablename() 和 setVariablename(),虽然没有明确要求。

你须要将 set 和 get 函数声明为公共的,以便对象能够访问这些函数。

矩阵功能函数

第三组要声明的函数是用于矩阵功能的。其语法与 get 和 set 函数语法以及任何正常的 C++ 函数彻底相同。你须要为输入变量指定返回数据类型、函数名称和数据类型。

例如,Gaussian 类有三个函数:evaluate、multiply 和 add。如下是如何在 gaussian.h 文件中声明这些函数的示范:

class Gaussian { .... public: ... //待评估函数 float evaluate (float); Gaussian multiply (Gaussian); Gaussian add (Gaussian); }; 

 

声明构造函数

Python 和 C++ 都有构造函数。构造函数定义了对象实例化时会发生什么。

Python 构造函数

它们定义了对象实例化时会发生什么。在 Python 中,语法是:

def __init__(self, variable1, variable2, ..., variablen): self.variable1 = variable1 self.variable2 = variable2 self.variablen = variablen 

C++ 构造函数声明

在 C++ 中,构造函数声明以下:

Classname (datatype for variable1, datatype for variable2, …, datatype for variablen); 

你也能够同时声明一个默认的构造函数。

Classname ();

实例化一个对象而不提供变量的值时,使用这个默认的构造函数。说得更具体一点,你将用一个二维向量来初始化一个矩阵变量。若是不提供二维向量,也可使用默认向量来初始化矩阵变量。第二种状况中,可使用空构造函数。

Gaussian 构造函数声明以下:

class Gaussian { private: ... public: ... Gaussian (); Gaussian (float, float); .... }; 
 

定义构造函数

声明了构造函数后,你须要在 .cpp 文件中实际定义它们。

构造函数定义的语法以下:

//空构造函数的语法 Classname::ClassName() { constructor function definition } // constructor function syntax Classname::ClassName(datatype variable1, datatype variable2, …, datatype variablen) { constructor function definition } 
 

你能够看到这在 Gaussian 类中是如何实现的:

Gaussian::Gaussian() {
    mu = 0; sigma2 = 1; } Gaussian::Gaussian (float average, float sigma) { mu = average; sigma2 = sigma; } 
 

请注意,构造函数不返回任何内容。它们只会初始化类变量。你可能还想知道,若是 mu 和 sigma2 是私有变量,函数定义如何能访问这两个变量。请记住,私有变量能够从类代码内部访问,但不能从类外部访问。

 

使用默认值初始化

在 Python 和 C++ 中,均可以在构造函数中使用默认值。在 Python 中,语法是:

def __init__(self, variable1 = default1, variable2 = default2, ..., variablen = defaultn): self.variable1 = variable1 self.variable2 = variable2 self.variablen = variablen 

C++ 也有相同功能,但语法可能和所指望的不同。默认值的定义实际上在 .h 文件函数定义中。下面一个加法类的简单例子,它包含两个整数并输出它们的总和。

如下为头文件 add.h:

class Add { public: int a; int b; Add(int, int second = 17); int addition(); }; 

这里是 add.cpp 中的定义:

# include "add.h" Add::Add(int first, int second) { a = first; b = second; } int Add::addition() { return a + b; } 

请注意,默认值是在头文件中声明的。如今,若是在实例化 add 对象时只指定了一个值,则变量 b 将具备默认值 17:

 
# include <iostream> # include "add.h" int main() { Add adder(5); std::cout << adder.addition() << std::endl; return 0; } 

上述代码输出值 22。

 

 
 

Set 和 Get 函数声明

对象不能直接访问私有变量,但借助于 Set 和 Get 函数,你的对象能够访问私有变量。本课前面的 Gaussian 对象展现了具体实现方法。

如下是 set 和 get 函数的声明:

class Gaussian { private: ... public: ... void setMu(float); void setSigma2(float); float getMu(); float getSigma2(); .... }; 

这里是函数定义:

void Gaussian::setMu (float average) { mu = average; } void Gaussian::setSigma2 (float sigma) { sigma2 = sigma; } float Gaussian::getMu () { return mu; } float Gaussian::getSigma2() { return sigma2; } 

定义 set 或 get 函数的语法与其余类函数(除构造函数外)相同:

return datatype Classname::functionname() { code to define the function; } 

实际上,get 和 set 函数是一种约定,而不是具备特殊语法的特殊函数。传统上,虽然没有明确要求,但咱们将这些函数命名为 getVariablename() 和 setVariablename()。

你须要将 set 和 get 函数声明为公共的,这样对象就能够访问这些函数了。

 

矩阵类的 set 和 get 函数

继续编写你的矩阵类代码。 使用 set 函数来修改 grid 变量。 全部三个私有变量(gird、rows、cols)都应该有函数。

#include <iostream>
#include <vector>
#include "matrix.h"

int main () {
    
    // TODO: Nothing to do here
    
    return 0;
}
# include "matrix.h" Matrix::Matrix() { std::vector <std:: vector <float> > initial_grid (10, std::vector <float>(5, 0.5)); grid = initial_grid; rows = initial_grid.size(); cols = initial_grid[0].size(); } Matrix::Matrix(std::vector <std:: vector <float> > initial_grid) { grid = initial_grid; rows = initial_grid.size(); cols = initial_grid[0].size(); } void Matrix::setGrid(std::vector< std::vector<float> > new_grid) { grid = new_grid; rows = new_grid.size(); cols = new_grid[0].size(); } std::vector< std::vector<float> > Matrix::getGrid() { return grid; } std::vector<int>::size_type Matrix::getRows() { return rows; } std::vector<int>::size_type Matrix::getCols() { return cols; }
# include <vector> class Matrix { private: std::vector< std::vector<float> > grid; std::vector<int>::size_type rows; std::vector<int>::size_type cols; public: //构造函数 Matrix (); Matrix (std::vector< std::vector<float> >); // set functions void setGrid(std::vector< std::vector<float> >); // get functions std::vector< std::vector<float> > getGrid(); std::vector<int>::size_type getRows(); std::vector<int>::size_type getCols();
 
 

矩阵函数

Matrix 类的最后一部分涉及到矩阵函数的实现。你须要尽量多地练习矩阵运算编程,包括加法、乘法、转置、求逆等。

咱们建议,你至少须要实现一个矩阵加法,以及一个名为 matrix_print 的函数,它使用 cout 将矩阵输出到终端。在本页最后给出的参考答案中,咱们还提供了matrix_transpose 函数的代码。

实现这些类的函数与实现本课前面的 get 和 set 函数是同样的。你将须要在 matrix.h 中声明函数,并在 matrix.cpp 中定义函数。通常语法也是同样的:

类函数声明语法

return datatype functionname(datatype for variable1, datatype for variable2, ..., datatype for variablen) 

类函数定义语法

return datatype Classname::functionname(datatype variable1, datatype variable2, ..., datatype variablen) { code defining the function; } 
 

编写矩阵函数

在本练习中,你将声明并定义将两个矩阵相加的矩阵类函数。如下是矩阵加法函数的输入和输出:

输入:

  • 一个矩阵,它将被添加到 grid 变量中

输出:

  • 包含 grid 变量矩阵和输入矩阵之和的一个矩阵

因为 matrix_addition 函数的输入是矩阵,所以须要使用 Matrix 类做为数据类型来声明并定义函数。这彷佛有点混乱,但和本课前面介绍的 Gaussian 类中的 mul 和 add 函数彻底相同。你可使用这些做为编写 matrix_addition 函数的指南。

如下是 gaussian.h 中的 mul 和 add 函数的函数声明,供参考:

Gaussian mul (Gaussian); Gaussian add (Gaussian); 

这两个函数都接收高斯值并输出高斯值。如下是 gaussian.cpp 的函数定义:

Gaussian Gaussian::mul(Gaussian other) {
    float denominator; float numerator; float new_mu; float new_var; denominator = sigma2 + other.getSigma2(); numerator = mu * other.getSigma2() + other.getMu() * sigma2; new_mu = numerator / denominator; new_var = 1.0 / ( (1.0 / sigma2) + (1.0 / other.sigma2) ); return Gaussian(new_mu, new_var); } Gaussian Gaussian::add(Gaussian other) { float new_mu; float new_sigma2; new_mu = mu + other.getMu(); new_sigma2 = sigma2 + other.getSigma2(); return Gaussian(new_mu, new_sigma2); } 
 

虽然 matrix_addition 函数的实现有所不一样,但通常结构与 Gaussian 示例中的 mul 和 add 函数相同。

你还须要编写一个 matrix_print 函数,该函数使用 cout 向终端输出一个矩阵。matrix_print 函数没有输入,也没有输出。

在 matrix.cpp 和 matrix.h 代码中填充 TODO 部分。

# include <vector>
# include <iostream>
# include <stdexcept>

# include <vector>

class Matrix
{
    private:

        std::vector< std::vector<float> > grid;
        std::vector<int>::size_type rows;
        std::vector<int>::size_type cols;

    public:

        // 构造函数
        Matrix ();
        Matrix (std::vector< std::vector<float> >);

        // set 函数
        void setGrid(std::vector< std::vector<float> >);

        // get 函数
        std::vector< std::vector<float> > getGrid();
        std::vector<int>::size_type getRows();
        std::vector<int>::size_type getCols();

        // 矩阵函数
        Matrix matrix_transpose();
        Matrix matrix_addition(Matrix);

        //矩阵打印
        void matrix_print();

};
# include "matrix.h"

Matrix::Matrix() {
    std::vector <std:: vector <float> > initial_grid (10, std::vector <float>(5, 0.5));
    grid = initial_grid;
    rows = initial_grid.size();
    cols = initial_grid[0].size();

}

Matrix::Matrix(std::vector <std:: vector <float> > initial_grid) {
    grid = initial_grid;
    rows = initial_grid.size();
    cols = initial_grid[0].size();
}

void Matrix::setGrid(std::vector< std::vector<float> > new_grid) {
    grid = new_grid;
    rows = new_grid.size();
    cols = new_grid[0].size();

}

std::vector< std::vector<float> > Matrix::getGrid() {
    return grid;
}

std::vector<int>::size_type Matrix::getRows() {
    return rows;
}

std::vector<int>::size_type Matrix::getCols() {
    return cols;
}

Matrix Matrix::matrix_transpose() {
    std::vector< std::vector<float> > new_grid;
    std::vector<float> row;

    for (int i = 0; i < cols; i++) {
        row.clear();

        for (int j = 0; j < rows; j++) {
            row.push_back(grid[j][i]); 
        }
        new_grid.push_back(row);
    }

    return Matrix(new_grid);
}

Matrix Matrix::matrix_addition(Matrix other) {

    if ((rows != other.getRows()) || (cols != other.getCols())) {
        throw std::invalid_argument( "matrices are not the same size" );
    }

    std::vector< std::vector<float> > othergrid = other.getGrid();

    std::vector< std::vector<float> > result;

    std::vector<float> new_row;

    for (int i = 0; i < rows; i++) {
        new_row.clear();
        for (int j = 0; j < cols; j++) {
            new_row.push_back(grid[i][j] + othergrid[i][j]);
        }
        result.push_back(new_row);
    }

    return Matrix(result);
}

void Matrix::matrix_print() {

    std::cout << std::endl;

    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            std::cout << grid[i][j] << " ";
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;
}

实例化一个对象

如今,是时候在程序中使用你的矩阵类了!C++ 中实例化对象的语法以下所示:

Classname objectname(inputs for initializing an object of Classname); 

而后,你就能够访问任何公共变量,如:

objectname.variablename

你还能够访问公共函数:

objectname.methodname(inputs)

请记住,你的程序没法访问任何私有变量或函数。这就是你须要为你的私有变量编写公共的 get 和 set 函数的缘由。

 

Gaussian.cpp 例子

在开始使用矩阵类以前,先看看 Gaussian.cpp 中 main.cpp 的一个例子:

# include <iostream>
# include "gaussian.h"

int main ()
{

    Gaussian mygaussian(30.0,20.0);
    Gaussian othergaussian(10.0,30.0);

    std::cout << "average " << mygaussian.getMu() << std::endl;
    std::cout << "evaluation " << mygaussian.evaluate(15.0) << std::endl;

    std::cout << "mul results sigma " << 
               mygaussian.mul(othergaussian).getSigma2() << std::endl;
    std::cout << "mul results average " << 
               mygaussian.mul(othergaussian).getMu() << std::endl;

    std::cout << "add results sigma " << 
               mygaussian.add(othergaussian).getSigma2() << std::endl;
    std::cout << "add results average " << 
               mygaussian.add(othergaussian).getMu() << std::endl;

    return 0;
}
 

如今轮到你编写矩阵对象了。下面提供了一些辅助代码,有一些 TODO 部分须要你完成。

 

 
//main.cpp 参考答案
# include <iostream>
# include <vector>
# include "matrix.h"

int main () {

    // 给变量 initial_grid 分配一个 7x5 矩阵
    // 矩阵中的全部值都是 0.4
    std::vector <std:: vector <float> > 
        initial_grid (7, std::vector <float>(5, 0.4));

    // TODO:使用初始 grid 变量来实例化一个矩阵对象
    // 矩阵对象应该写做 matrixa
    Matrix matrixa(initial_grid);

    // TODO:使用 matrix_print() 方法打印出 matrixa
    matrixa.matrix_print();

    // TODO:打印出 matrixa 中的行数。你须要
    //使用 getRows() 函数和 std::cout
    std::cout << matrixa.getRows();

    // TODO:打印出 matrixa 中的列数 
    std::cout << matrixa.getCols();

    // TODO:取矩阵的转置并把结果存储在
    //一个名叫 transposea 的变量里
    Matrix transposea = matrixa.matrix_transpose();

    // TODO:打印出 transposea
    transposea.matrix_print();

    // 如今你须要使用另外一个名为 matrixb 的 7x5 矩阵,来 
    //给出 matrix_addition 函数的结果

    // 7x5 二维矩阵,全部值均为 0.2
    std::vector <std:: vector <float> > 
        second_grid (7, std::vector <float>(5, 0.2));

    // TODO:实例化一个叫作 matrixb 的对象使用 second_grid
    // 变量做为初始化 matrixb 的输入
    Matrix matrixb(second_grid);

    // TOOD:matrixa 和 matrixb 相加。将结果存储在一个新的矩阵中
    //变量名为 matrixsum
    Matrix matrixsum(matrixa.matrix_addition(matrixb));

    // TODO:打印出 matrixsum 变量中包含的矩阵
    matrixsum.matrix_print();

    return 0;
}

编译你的程序

若是你的计算机上没有在本地运行 C++,如今是完成这个任务的好机会!

下面是在本地计算机上编译并运行矩阵代码的简要说明。把你的 main.cpp、matrix.cpp 和 matrix.h 文件放到同一个目录下。在 Linux 和 Mac 上,你可使用以下命令编译代码:

g++ main.cpp matrix.cpp

或者你的系统中任何相同功能的程序或编译器。要编译代码,你须要编译 main.cpp 和 matrix.cpp。而后,你能够执行你的代码,参考命令以下:

./a.out
相关文章
相关标签/搜索