面向对象基本原理

今天终于开始学习面向对象了,b 站大学真是太牛逼啦!

浙大翁恺老师的课讲得很清楚,疯狂安利!

【浙江大学】面向对象程序设计,教授:翁恺

面向对象基本原理

面向对象程序设计,object-oriented-programming (OOP),在这种方式的程序设计中,把每一个变量看作是一个对象,通过调用对象提供的功能函数达到目的。

面向对象与面向过程编程的区别

所谓面向过程,即程序按照主函数从上到下的顺序依次调用各种函数和变量,通过数据与指令流的方式控制整个程序,最终达到目的。

而面向对象不一样,面向对象的思想并不关注程序当前执行到哪一步,它关心的是程序中存在什么东西,以及这些“东西”之间如何联系。通过把这些东西有序的组合起来,再依靠这些“东西”之间传递的消息来完成调用,达到目的。

简单点来说,面向过程就是程序员一步一步告诉程序该怎么做;面向对象是先告诉程序内各个模块:当收到指令 A 的时候怎么做,收到指令 B 的时候又该怎么做,最后只用告诉程序指令 A 或者指令 B ,让程序内的不同模块开始传递信息,按我们预先设定好的方式解决问题,我们只需要等结果就行了。

对象的定义

说了一大顿,那么何为“对象”?实际上,任何可以被称作“东西”的东西,都可以称为“对象”。

比如说一个苹果,一个水杯,坐标系内一个点,等等等等。

这些东西又包含它自己的一些特性,比如苹果有颜色、大小,一个点有它自己的坐标,水杯可以装水,也有它自己的颜色……一切东西都有它自己的特性。

我们把这些物体的特性称为对象的“属性”,对于计算机代码而言,属性也就是一个对象中包含的数据啦。

除了这些特殊的属性,面向对象还要求对象具有一定的功能。

比如水杯,它可以往里装水,也可以往外倒水;平面内一个点,它可以拥有把它的基本信息(也就是坐标)告诉我们的功能。

我们把这些物体所包含的功能称为对象提供的“服务”,也就是“这个对象支持我们对它做什么”的意思。对于计算机代码而言,服务通常以函数的形式出现。

总的来说,对象就是上面说的 属性 + 服务。

类的概念

有了对象(也就是物品)自然也就有了类的区分。

现实生活中,博物学给各种声明都区分了界门纲目科属种的归类,这就是一种类的区分。比如有一只花猫和一只黑猫,我们可以把他们简单的归为一类,即“猫”;又有两个一高一矮的水杯,我们也可以把他们归为一类,即“杯子”。

仔细思考一下我们为什么这么做,究其原因就是他们拥有相同的特征和功能:猫都有胡须毛发(属性),主人发出“叫”的指令,它们可以喵喵叫(功能);水杯都可以储水(特征),也可以接水和倒水(功能)。

简单粗暴一点,对于程序设计中的对象,只要拥有相同的属性和服务,我们就认为它们是同一类。

同一类中的对象,因为他们的服务都是相同的,所以它们也能接受相同的指令。特别的,反过来说,如果两个对象可以接受的所有指令都完全相同,那么我们也可以把它们认为是同一类。

类与对象

在自然界中,人们常常是发现一个新事物之后,再把它归类。但在计科中,是我们先创造一个类,规定他拥有什么样的属性和服务功能,再去创造新事物(即对象)。

在 C++ 中,声明类用关键字 Class 表示。

class Cat
{
  public:
    Cat(const string a, const string b, const bool c)
    {
      name = a, color = b, cute = c;
    }
    void GetInfomation() const
    {
      cout << name << '\n';
      cout << color << '\n';
      if(cute)
        cout << "cute!" << '\n';
      else
        cout << "not so cute..." << '\n';
    }
    void Meow() const
    {
      cout << "Meow" << '\n';
    }
  private:
    string name, color;
    bool cute;
}garfield;

这段代码中,我创建了一个名字是 Cat 的类(电子猫咪),并赋予它三个特征:name, color 和 cute,以及通过函数实现输出基本信息、喵喵叫的功能。

然后我在这个类的框架下声明了一个变量 garfield, 这就是归属 Cat 类的一个对象。它具有 Cat 类规定的所有属性和服务,即上面说的 name, color 和 cute,以及输出它自己的基本信息、喵喵叫的功能。

至于代码里面的 privatepublic 关键字,我们下一节再细说。

面向对象的要求

这里有一个像煎鸡蛋的图,面向对象的核心思想就是这个煎蛋。

煎蛋的蛋黄是数据 (Data),煎蛋的蛋清是操作 (Operations),OOP 要求我们在程序设计的时候不可以直接对里面的蛋黄进行操作,只能通过外面蛋清提供的服务来间接的控制蛋黄里的数据,也即“对象中的元素受到保护”。

对象通过它提供的服务对内数据提供指令交流和保护,对外部的操作进行反馈。这些服务就是所谓的“接口”,即外部程序在访问对象的时候只能通过这些“接口”向对象发布指令和接受对象反馈的信息,但是不可以直接访问对象内的数据

拿这两段代码举例子,它们都得到了一个二维坐标点的详细坐标信息,但实现方式不同:

struct Point2d{
  Point2d(const int a, const int b)
  {
    x = a, y = b;
  }
  int x, y;
};
void PrintPoint2d(const Point2d * const p)
{
  cout << p -> x << ' ' << p -> y;
}
int main()
{
  Point2d A(2, 3);
  PrintPoint2d(&A);
}

这段代码是典型的面向过程思想,通过外部函数来直接查询对象内的数据。

class Point2d
{
  private:
    int x, y;
  public:
    Point2d(const int a, const int b)
    {
      x = a, y = b; 
    }
    void PrintPoint2d() const 
    {
      cout << x << ' ' << y;
    }
};
int main()
{
  Point2d A(2, 3);
  A.PrintPoint2d();
}

这段代码是面向对象的思想,通过对象自己内部的功能(接口)获得数据。

private 就是对象私有的属性,它表示这些数据是对象私有的,不能从外部直接进行访问;public 就是外面的公用接口,我们只可以调用这些接口中的数据和函数。

为什么要这样做?

面向对象设计的核心目的是让代码的结构变得松散而灵活。

用灯泡和灯管举例子。

  • 假设灯泡和灯座是两个不同的对象,他们通过接口(也就是现实中的螺口)相连接,如果我想换一个灯泡,那么只需要把灯泡拧下来换上新的就可以了。面向对象思想就是通过接口的方式实现代码的可更新性与可扩展性,因为要更新灯泡部分代码的话,我们就不用管灯座部分的代码。

  • 现在再假设灯泡和灯管是一体的,他们直接出厂的时候就焊在一起了,那么想换一个灯泡就很困难,因为他们之间的联系太过紧密,牵一发而动全身。这导致代码的可扩展性变得差一些。

现实中程序员一般可以分为两类

  1. class creater,负责写类的程序员,他们负责写类,实现某些功能。
  2. client programmer,负责利用类给出的功能实现其他功能的程序员。

当写类的程序员想要维护更新他的类的时候,只需要直接改他自己的代码就行了——只要保证原接口的调用方式不变,那么 client programmer 仍可以正常调用,因此他就不用修改他的代码。

这样是很方便的。

posted @ 2023-10-25 08:56  ZTer  阅读(34)  评论(0编辑  收藏  举报