Pascal 面向对象

  • 面向对象

    我们可以想象我们的宇宙是由不同的物体(例如太阳,地球,月亮等)组成的。同样,我们可以想象我们的汽车是由不同的物体(例如车轮,转向,齿轮等)组成的。同样,存在面向对象的编程概念,假设一切都是对象,并使用不同的对象来实现软件。在Pascal中,有两种结构数据类型用于实现现实世界对象-
    • 对象类型
    • 类类型
  • 面向对象的概念

    在详细介绍之前,让我们定义与面向对象的Pascal相关的重要Pascal术语。
    • 对象 - 对象是一种特殊的记录,其中包含诸如记录之类的字段;但是,与记录不同,对象包含过程和函数作为对象的一部分。这些过程和函数作为与对象类型关联的方法的指针而保留。
    • - 类的定义与对象的定义几乎相同,但是创建它们的方式有所不同。类分配在程序的堆上,而对象分配在堆栈上。它是指向对象的指针,而不是对象本身。
    • 类的实例化 - 实例化意味着创建该类类型的变量。由于类只是一个指针,因此在声明类类型的变量时,将只为该指针分配内存,而不为整个对象分配内存。仅当使用其构造函数之一实例化该对象时,才会为该对象分配内存。类的实例也称为“对象”,但不要将它们与“对象Pascal对象”混淆。在本教程中,我们将为Pascal Objects编写“Object”,为概念性对象或类实例编写“object”。
    • 成员变量 - 这些是在类或对象内定义的变量。
    • 成员函数 -这些是在类或对象内定义的函数或过程,用于访问对象数据。
    • 成员的可见性 -对象或类的成员也称为字段。这些字段具有不同的可见性。可见性是指成员的可访问性,即这些成员可访问的确切位置。对象具有三个可见性级别:public,private和protected。类具有五种可见性类型:public, private, strictly private, protected 和 published.。我们将详细讨论可见性。
    • 继承 - 当通过继承父类的现有功能来定义类时,则可以说它是继承的。在此,子类将继承父类的全部或部分成员函数和变量。对象也可以被继承。
    • 父类 - 由另一个类继承的类。这也称为基类或超类。
    • 子类 - 从另一个类继承的类。这也称为子类或派生类。
    • 多态性 - 这是一个面向对象的概念,其中相同的功能可以用于不同的目的。例如,函数名称将保持不变,但是它可以使用不同数量的参数,并且可以执行不同的任务。Pascal类实现多态。对象不实现多态。
    • 重载 - 这是一种多态性,其中某些或所有运算符根据其自变量的类型具有不同的实现。类似的功能也可以通过不同的实现来重载。Pascal类实现重载,但对象不实现。
    • 数据抽象 -隐含(摘要)实现细节的任何数据表示形式。
    • 封装 - 指一个概念,其中我们将所有数据和成员函数封装在一起以形成一个对象。
    • 构造函数 -指的是一种特殊类型的函数,只要有一个类或一个对象构成一个对象,就会自动调用该函数。
    • 析构函数-指的是一种特殊类型的函数,只要删除对象或类或超出范围,就会自动调用该函数。
  • 定义 Pascal 对象

    使用类型声明来声明对象。对象声明的一般形式如下-
    
    type object-identifier = object  
       private
       field1 : field-type;  
       field2 : field-type;  
       ...
       public
       procedure proc1;  
       function f1(): function-type;
       end;  
    var objectvar : object-identifier;
    
    让我们定义一个Rectangle Object,它具有两个整数类型的数据成员- 长度和宽度,以及一些操作这些数据成员的成员函数以及一个绘制矩形的过程。
    
    type 
       Rectangle = object  
       private  
          length, width: integer; 
       
       public  
          constructor init;  
          destructor done;  
          
          procedure setlength(l: inteter);  
          function getlength(): integer;  
          
          procedure setwidth(w: integer);  
          function getwidth(): integer;  
          
          procedure draw;
    end;
    var
       r1: Rectangle;
       pr1: ^Rectangle;
    
    创建对象后,您将能够调用与该对象相关的成员函数。一个成员函数将只能处理相关对象的成员变量。下面的示例演示如何为两个矩形对象设置长度和宽度,以及如何通过调用成员函数来绘制它们。
    
    r1.setlength(3);
    r1.setwidth(7);
    
    writeln(' Draw a rectangle: ', r1.getlength(), ' by ' , r1.getwidth());
    r1.draw;
    new(pr1);
    pr1^.setlength(5);
    pr1^.setwidth(4);
    
    writeln(' Draw a rectangle: ', pr1^.getlength(), ' by ' ,pr1^.getwidth());
    pr1^.draw;
    dispose(pr1);
    
    以下是一个完整的示例,展示了如何在Pascal中使用对象-
    
    program exObjects;
    type 
       Rectangle = object  
       private  
          length, width: integer; 
       
       public  
          procedure setlength(l: integer);
          function getlength(): integer;  
          
          procedure setwidth(w: integer);  
          function getwidth(): integer;  
          
          procedure draw;
    end;
    var
       r1: Rectangle;
       pr1: ^Rectangle;
    
    procedure Rectangle.setlength(l: integer);
    begin
       length := l;
    end;
    
    procedure Rectangle.setwidth(w: integer);
    begin
       width :=w;
    end;
    
    function Rectangle.getlength(): integer;  
    begin
       getlength := length;
    end;
    
    function Rectangle.getwidth(): integer;  
    begin
       getwidth := width;
    end;
    
    procedure Rectangle.draw;
    var 
       i, j: integer;
    begin
       for i:= 1 to length do
       begin
         for j:= 1 to width do
            write(' * ');
         writeln;
       end;
    end;
    
    begin
       r1.setlength(3);
       r1.setwidth(7);
       
       writeln('Draw a rectangle:', r1.getlength(), ' by ' , r1.getwidth());
       r1.draw;
       new(pr1);
       pr1^.setlength(5);
       pr1^.setwidth(4);
       
       writeln('Draw a rectangle:', pr1^.getlength(), ' by ' ,pr1^.getwidth());
       pr1^.draw;
       dispose(pr1);
    end.
    
    尝试一下
    编译并执行上述代码后,将产生以下结果-
    
    Draw a rectangle:3 by 7
    * * * * * * * 
    * * * * * * * 
    * * * * * * * 
    Draw a rectangle:5 by 4
    * * * * 
    * * * * 
    * * * * 
    * * * * 
    * * * * 
    
  • 对象成员的可见性

    可见性表示对象成员的可访问性。Pascal对象成员具有三种可见性-
    可见性 说明
    Public 成员可以被程序单元之外的其他单元使用
    Private 成员只能在当前单元中访问。
    Protected 成员仅可用于从父对象派生的对象。
    默认情况下,对象的字段和方法是公共(pulbic)的,并被导出到当前单元之外。
  • Pascal 对象的构造函数和析构函数

    构造函数是一种特殊的方法,每当创建一个对象时,它们便会自动被调用。您只需在Pascal中声明带有关键字构造函数的方法即可创建一个构造函数。通常,方法名称为Init,但是您可以提供自己的任何有效标识符。您可以根据需要将任意数量的参数传递给构造函数。
    析构函数是在销毁对象期间调用的方法。析构函数方法会破坏构造函数创建的任何内存分配。下面的示例将为Rectangle类提供一个构造函数和一个析构函数,它们将在创建对象时初始化矩形的长度和宽度,并在超出范围时销毁矩形。
    以下示例说明了上述某些函数的用法-
    
    program exObjects;
    type 
       Rectangle = object  
       private  
          length, width: integer; 
       public  
          constructor init(l, w: integer);
          destructor done;
          
          procedure setlength(l: integer);
          function getlength(): integer;  
          
          procedure setwidth(w: integer);  
          function getwidth(): integer;  
          
          procedure draw;
    end;
    
    var
       r1: Rectangle;
       pr1: ^Rectangle;
    
    constructor Rectangle.init(l, w: integer);
    begin
       length := l;
       width := w;
    end;
    
    destructor Rectangle.done;
    begin
       writeln(' Desctructor Called');
    end; 
    
    procedure Rectangle.setlength(l: integer);
    begin
       length := l;
    end;
    
    procedure Rectangle.setwidth(w: integer);
    begin
       width :=w;
    end;
    
    function Rectangle.getlength(): integer;  
    begin
       getlength := length;
    end;
    
    function Rectangle.getwidth(): integer;  
    begin
       getwidth := width;
    end;
    
    procedure Rectangle.draw;
    var 
       i, j: integer;
    begin
       for i:= 1 to length do
       begin
          for j:= 1 to width do
             write(' * ');
          writeln;
       end;
    end;
    
    begin
       r1.init(3, 7);
       writeln('Draw a rectangle:', r1.getlength(), ' by ' , r1.getwidth());
       r1.draw;
       new(pr1, init(5, 4));
       
       writeln('Draw a rectangle:', pr1^.getlength(), ' by ',pr1^.getwidth());
       pr1^.draw;
       pr1^.init(7, 9);
       
       writeln('Draw a rectangle:', pr1^.getlength(), ' by ' ,pr1^.getwidth());
       pr1^.draw;
       dispose(pr1);
       r1.done;
    end.
    
    尝试一下
    编译并执行上述代码后,将产生以下结果:
    
    Draw a rectangle: 3 by 7
    * * * * * * *
    * * * * * * *
    * * * * * * *
    Draw a rectangle: 5 by 4
    * * * *
    * * * *
    * * * *
    * * * *
    * * * *
    Draw a rectangle: 7 by 9
    * * * * * * * * *
    * * * * * * * * *
    * * * * * * * * *
    * * * * * * * * *
    * * * * * * * * *
    * * * * * * * * *
    * * * * * * * * *
    Destructor Called
    
  • Pascal 对象的继承

    Pascal 对象可以选择从父对象继承。以下程序说明了Pascal对象中的继承。让我们创建另一个名为TableTop的对象,该对象继承自Rectangle对象。
    
    program exObjects;
    type 
       Rectangle = object  
       private  
          length, width: integer; 
       public  
          procedure setlength(l: integer);  
          function getlength(): integer;  
          procedure setwidth(w: integer);  
          function getwidth(): integer;  
          procedure draw;
    end;
    
    TableTop = object (Rectangle)
       private
         material: string;
       public
          function getmaterial(): string;
          procedure setmaterial( m: string);
          procedure displaydetails;
          procedure draw;
    end;
    
    var
       tt1: TableTop;
    
    procedure Rectangle.setlength(l: integer);
    begin
       length := l;
    end;
    
    procedure Rectangle.setwidth(w: integer);
    begin
       width :=w;
    end;
    
    function Rectangle.getlength(): integer;  
    begin
       getlength := length;
    end;
    
    function Rectangle.getwidth():integer;
    begin
       getwidth := width;
    end;
    
    procedure Rectangle.draw;
    var 
       i, j: integer;
    begin
       for i:= 1 to length do
       begin
          for j:= 1 to width do
             write(' * ');
          writeln;
      end;
    end;
    
    function TableTop.getmaterial(): string;
    begin
       getmaterial := material;
    end;
    
    procedure TableTop.setmaterial( m: string);
    begin
       material := m;
    end;
    
    procedure TableTop.displaydetails;
    begin
       writeln('Table Top: ', self.getlength(), ' by ' , self.getwidth());
       writeln('Material: ', self.getmaterial());
    end;
    
    procedure TableTop.draw();
    var
       i, j: integer;
    begin
       for i:= 1 to length do
       begin
          for j:= 1 to width do
             write(' * ');
       writeln;
       end;
       writeln('Material: ', material);
    end;
    
    begin
       tt1.setlength(3);
       tt1.setwidth(7);
       tt1.setmaterial('Wood');
       tt1.displaydetails();
       writeln;
       writeln('Calling the Draw method');
       tt1.draw();
    end. 
    
    尝试一下
    以下是应注意的重点-
    • Tabletop对象继承了Rectangle对象的所有成员。
    • TableTop中也有一个draw方法。当TableTop类调用draw方法时,TableTop上的draw被调用。
    • 有一个名为self的隐式实例,它引用对象的当前实例。
    编译并执行上述代码后,将产生以下结果:
    
    Table Top: 3 by 7
    Material: Wood
    
    Calling the Draw Method 
    * * * * * * *
    * * * * * * *
    * * * * * * *
    Material: Wood