首页 > 其他分享 >第11章 使用类——再谈重载:矢量类(一)

第11章 使用类——再谈重载:矢量类(一)

时间:2024-04-06 21:13:00浏览次数:25  
标签:11 set const double 矢量 再谈 Vector 重载 ang

本文章是作者根据史蒂芬·普拉达所著的《C++ Primer Plus》而整理出的读书笔记,如果您在浏览过程中发现了什么错误,烦请告知。另外,此书由浅入深,非常适合有C语言基础的人学习,感兴趣的朋友可以自行阅读此书籍。

矢量,是工程和物理中使用的一个术语,它是一个有大小和方向的量。例如,推东西时,推的效果将取决于推力的大小和推的方向。
同时,矢量也支持相加,首先,画一个矢量,然后从第一个矢量的尾部开始画第二个矢量。最后从第一个矢量的开始处向第二个矢量的结尾处画一个矢量。第三个矢量表示前两个矢量的和。注意,两个矢量之和的长度可能小于它们的长度之和。

显然无法使用一个数来表示矢量,因此应创建一个类来表示矢量。其次,矢量与普通数学运算有相似之处,因此应重载运算符。

出于简化的目的,本节将实现一个二维矢量(如屏幕位移)。描述二维矢量只需要两个数,但可以选择到底使用哪两个数:

  • 可以用大小(长度)和方向(角度)描述矢量;
  • 可以用分量x和y表示矢量。

两个分量分别是水平矢量(x分量)和垂直矢量(y分量),将其相加可以得到最终的矢量。例如,可以这样描述点的运动:向右移动30个单位,再向上移动40个单位。这将把该点沿与水平方向呈53.1度的方向移动50个单位(没错,就是勾股定理),因此,水平分量为30个单位、垂直分量为40个单位的矢量,与长度为50个单位、方向为53.1度的矢量相同。

因此在设计这个类时,当用户修改了矢量的一种表示时,对象将自动更新另一种表示。

以下是类声明的代码:

//vect.hpp
#ifndef _VECTOR_H_
#define _VECTOR_H_
#include <iostream>
namespace VECTOR
{
  class Vector
  {
  public:
    enum Mode{RECT, POL};

  private:
    double x;
    double y;
    double mag;
    double ang;
    Mode mode;
    void set_mag();
    void set_ang();
    void set_x();
    void set_y();

  public:
    Vector();
    Vector(double n1, double n2, Mode form = RECT);
    void reset(double n1, double n2, Mode form = RECT);
    ~Vector();
    double xval() const {return x;}
    double yval() const {return x;}
    double magval() const {return mag;}
    double angval() const {return ang;}
    void polar_mode();
    void rect_mode();
    
    Vector operator+(const Vector& b) const;
    Vector operator-(const Vector& b) const;
    Vector operator-() const;
    Vector operator* (double n) const;
    
    friend Vector operator*(double n, const Vector& a);
    friend std::ostream & operator<<(std::ostream & os, const Vector& v);
  };
}//end namespace VECTOR

#endif 

以下类实现代码:

//vect.cpp
#include "cmath"
#include "vect.hpp"

using std::sqrt;
using std::sin;
using std::cos;
using std::atan;
using std::atan2;
using std::cout;
using std::endl;

namespace VECTOR
{

    const double Rad_to_deg = 45.0 / atan(1.0);

    void Vector::set_mag()
    {
      mag = sqrt(x * x + y * y);      
    }

    void Vector::set_ang()
    {
      if (x == 0.0 && y == 0.0)
        ang = 0.0;
      else
        ang = atan2(y, x);
    }

    void Vector::set_x()
    {
      x = mag * cos(ang);
    }

    void Vector::set_y()
    {
      y = mag * sin(ang);    
    }

    Vector::Vector()
    {
      x = y = mag = ang = 0.0;
      mode = RECT;
    }

    Vector::Vector(double n1, double n2, Mode form)
    {
      mode = form;
      if(form == RECT)
      {
        x = n1;
        y = n2;
        set_mag();
        set_ang();
      }
      else if (form == POL)
      {
        mag = n1;
        ang = n2 / Rad_to_deg;
        set_x();
        set_y();
      }
      else{
        cout << "Incorrect 3rd argument to Vector() --";
        cout << "vector set to 0\n";
        x = y = mag = ang = 0.0;
        mode = RECT;
      }
      
    }

    void Vector::reset(double n1, double n2, Mode form)
    {
      mode = form;
      if(form == RECT)
      {
        x = n1;
        y = n2;
        set_mag();
        set_ang();
      }
      else if (form == POL)
      {
        mag = n1;
        ang = n2 / Rad_to_deg;
        set_x();
        set_y();
      }
      else{
        cout << "Incorrect 3rd argument to Vector() --";
        cout << "vector set to 0\n";
        x = y = mag = ang = 0.0;
        mode = RECT;
      }
    }

    Vector::~Vector()
    {

    }

    void Vector::polar_mode()
    {
      mode = POL;
    }

    void Vector::rect_mode()
    {
      mode = RECT;
    }

    Vector Vector::operator+(const Vector& b) const
    {
      return Vector(x + b.x, y + b.y);            //看似只处理了直角坐标,实际上构造函数中会实时更新极坐标
    }

    Vector Vector::operator-(const Vector& b) const
    {
      return Vector(x - b.x, y - b.y);
    }

    Vector Vector::operator-() const
    {
      return Vector(-x, -y);
    }

    Vector Vector::operator* (double n) const
    {
      return Vector(n * x, n * y);
    }
    
    Vector operator*(double n, const Vector& a)
    {
      return a * n;
    }

    std::ostream & operator<<(std::ostream & os, const Vector& v)
    {
      if (v.mode == Vector::RECT)
      {
        os << "(x, y) = (" << v.x << ", " << v.y << ")";
      }
      else if(v.mode == Vector::POL)
      {
        os << "(m, a) = (" << v.mag << ", " << v.ang * Rad_to_deg << ")"; 
      }  
      else
      {
        os << "Vector object mode is invalid";
      }
      return os;
    }
}//end namespace VECTOR

可以使用Vector类来模拟随机漫步问题:

随机漫步问题,指的是,将一个人领到街灯柱下。这个人开始走动,但每一步的方向都是随机的(与前一步不同)。这个问题的一种表述是,这个人走到离灯柱50英尺处需要多少步。

#include <iostream>
#include <cstdlib>
#include <ctime>
#include "vect.hpp"

int main()
{
    using namespace std;
    using VECTOR::Vector;

    srand(time(0));
    double direction;
    Vector step;
    Vector result(0.0, 0.0);
    unsigned long steps = 0;
    double target;
    double dstep;
    cout << "请输入目标距离(按任意字母退出): ";
    while (cin >> target)
    {
        cout << "输入步长:";
        if (!(cin >> dstep))
        {
            break;
        }

        while (result.magval() < target)
        {
            direction = rand() % 360;                                     
            step.reset(dstep, direction, Vector::POL);                    //新的一步,新的方向
            result = result + step;                                       
            steps ++ ;
        }

        cout << "走了" << steps << "步后,当前位置:\n";
        cout << result << endl;
        result.polar_mode();
        cout << "or\n" << result << endl;

        cout << "平均每步向外距离 = "
            << result.magval()/steps << endl;
        steps = 0;
        result.reset(0.0, 0.0);
        cout << "请输入目标距离(按任意字母退出): ";
    }
    cout << "Bye!\n";
    cin.clear();
    while (cin.get() != '\n')
    {
        continue;
    }
    
    return 0;
}

程序运行结果如下:
请输入目标距离(按任意字母退出): 50
输入步长:1
走了3553步后,当前位置:
(x, y) = (28.9761, -41.0075)
or
(m, a) = (50.2118, -54.7547)
平均每步向外距离 = 0.0141322
请输入目标距离(按任意字母退出): 50
输入步长:2
走了934步后,当前位置:
(x, y) = (10.1108, -49.3875)
or
(m, a) = (50.4119, -78.43)
平均每步向外距离 = 0.0539742
请输入目标距离(按任意字母退出): 50
输入步长:1
走了1262步后,当前位置:
(x, y) = (-33.2925, -38.2832)
or
(m, a) = (50.7345, -131.011)
平均每步向外距离 = 0.0402017
请输入目标距离(按任意字母退出): q
Bye!

原书中有这么一句话写得很好:
如果发现自己在随机漫步时,请保持自信,迈大步走。虽然在蜿蜒前进的过程中仍旧无法控制前进的方向,但至少会走得远一点。

加油!

标签:11,set,const,double,矢量,再谈,Vector,重载,ang
From: https://www.cnblogs.com/superbmc/p/18111865

相关文章

  • CF1149D Abandoning Roads 题解
    Description一张\(n\)个点\(m\)条边的无向图,只有\(a,b\)两种边权(\(a<b\)),对于每个\(i\),求图中所有的最小生成树中,从\(1\)到\(i\)距离的最小值。\(2\leqn\leq70,n-1\leqm\leq200,1\leqa<b\leq10^7\)。Solution先考虑一个最小生成树是什么样的形态,显然保留边权......
  • C++11中auto与decltype的区别与联系深入解析
    文章目录一、引言二、auto关键字及其特性1、auto的基本定义与用途2、auto在类型推导中的应用3、auto的局限性及需要注意的问题三、decltype关键字及其特性1、decltype的基本定义与用途2、decltype在类型推导中的应用3、decltype的局限性及需要注意的问题四、auto与decl......
  • 17天【代码随想录算法训练营34期】第六章 二叉树part04(● 110.平衡二叉树 ● 257.
    110.平衡二叉树#Definitionforabinarytreenode.#classTreeNode:#def__init__(self,val=0,left=None,right=None):#self.val=val#self.left=left#self.right=rightclassSolution:defgetDepth(self,root):......
  • P2495 [SDOI2011] 消耗战
    P2495[SDOI2011]消耗战虚树优化dp模板题考虑\(m=1\)。只需要简单的树形dp,设\(f_i\)表示\(i\)子树中的关键点都到不了\(i\)点的最小代价。转移枚举子节点\(v\),有:若\(v\)点为关键点,\(f_u=f_u+w(u,v)\)。否则,\(f_u=f_u+\min(f_v,w(u,v))\)。如果每次询问都跑一遍......
  • 20211325高进涛加密API研究
    密码引擎-加密API研究 Content任务详情0.研究学习原始文档CryptoAPIPKCS#11GM/T0016-2012智能密码钥匙密码应用接口规范GM/T0018-2012密码设备应用接口规范1.总结这些API在编程中的使用方式CryptoAPIPKCS#11SKF2.列出这些API包含的函数,进行分类,并总结它......
  • 计算机msvcp110.dll丢失修复
    MSVCP110.dll是一个属于MicrosoftVisualC++运行时库的动态链接库(DLL)文件。具体而言,这个文件是MicrosoftVisualC++2012RedistributablePackage的一部分,主要用于支持那些使用VisualStudio2012版本的C++编译器编译的应用程序运行时所需的基本函数和类库。 ......
  • 1311. 分跳绳
    题目:分跳绳问题描述:学校新买来m根跳绳,每个班分n根,最多可以分给几个班的同学?还剩多少根?输入&输出:接下来,直接献上代码:(C++)#include<iostream>usingnamespacestd;intmain(){intm,n;cin>>m>>n;cout<<m/n<<""<<m%n;return0;} 记得点赞+关......
  • FPGA入门笔记011_A——嵌入式块RAM的使用
    1、Cyclone-II系列FPGA内部结构图1——Altera公司Cyclone-II系列FPGA内部结构​ 如上图所示是Altera公司Cyclone-II系列FPGA内部结构,个模块作用如下:​ PLL锁相环—对时钟进行管理。​ IOEs—管脚单元,配置管脚,设置输入输出。​ 逻辑阵列—实现组合、时序逻辑。​ 块RAM......
  • 16天【代码随想录算法训练营34期】第六章 二叉树part03(● 104.二叉树的最大深度 559
    104.二叉树的最大深度#Definitionforabinarytreenode.#classTreeNode:#def__init__(self,val=0,left=None,right=None):#self.val=val#self.left=left#self.right=rightclassSolution:defmaxDepth(self,root:O......
  • PS1117-XX系列800 mA低噪声线性稳压器
    这份文件是关于PS1117-XX系列800mA低噪声线性稳压器的产品规格说明。以下是其核心内容的概要:产品特性(FEATURES)产品特性详细描述如下:1.**多种输出电压版本**:PS1117-XX系列线性稳压器提供了多种固定输出电压版本,包括1.5V、1.8V、2.5V、2.85V、3.3V、5V,以及可调版本,......