Pascal - 面向对象

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

  • 对象类型
  • 类类型

面向对象的概念

在详细介绍之前,让我们定义与面向对象 Pascal 相关的重要 Pascal 术语。

  • 对象 − 对象是一种特殊的记录,它包含像记录一样的字段; 然而,与记录不同,对象包含过程和函数作为对象的一部分。 这些过程和函数作为指向与对象类型关联的方法的指针。

  • − 类的定义方式与对象几乎相同,但它们的创建方式有所不同。 类分配在程序的堆上,而对象分配在堆栈上。 它是指向对象的指针,而不是对象本身。

  • 类的实例化 − 实例化意味着创建该类类型的变量。 由于类只是一个指针,因此当声明类类型的变量时,只会为该指针分配内存,而不是为整个对象分配内存。 仅当使用其构造函数之一实例化该对象时,才会为该对象分配内存。 类的实例也称为"对象",但不要将它们与 Object Pascal 对象混淆。 在本教程中,我们将为 Pascal 对象编写"Object",为概念对象或类实例编写"object"。

  • 成员变量 − 这些是在类或对象内定义的变量。

  • 成员函数 − 这些是在类或对象内定义的函数或过程,用于访问对象数据。

  • 成员的可见性 − 对象或类的成员也称为字段。 这些字段具有不同的可见性。 可见性是指成员的可访问性,即可以访问这些成员的确切位置。 对象具有三个可见性级别:公共、私有和受保护。 类有五种可见性类型:公共、私有、严格私有、受保护和发布。 我们将详细讨论可见性。

  • 继承 − 当一个类通过继承父类的现有功能来定义时,就称它是继承的。 这里子类将继承父类的全部或部分成员函数和变量。 对象也可以被继承。

  • 父类 − 一个类被另一个类继承。 这也称为基类或超类。

  • 子类 − 一个类继承另一个类。 这也称为子类或派生类。

  • 多态性 − 这是一个面向对象的概念,其中相同的功能可以用于不同的目的。 例如,函数名称将保持不变,但可能采用不同数量的参数并且可以执行不同的任务。 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;

让我们定义一个矩形对象,它有两个整数类型数据成员 - lengthwidth 以及一些操作这些数据成员的成员函数和一个绘制矩形的过程 。

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 对象成员具有三种类型的可见性 −

Sr.No 可见性和辅助功能
1

Public

成员可供项目单位以外的其他单位使用

2

Private

成员只能在当前单位访问。

3

Protected

这些成员仅适用于父对象的后代对象。

默认情况下,对象的字段和方法是公共的,并导出到当前单元之外。

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 中也有一个绘制方法。 当使用 TableTop 对象调用 draw 方法时,将调用 TableTop 的绘制。

  • 有一个名为 self 的隐式实例,它引用该对象的当前实例。

当上面的代码被编译并执行时,会产生以下结果 −

Table Top: 3 by 7
Material: Wood

Calling the Draw Method 
* * * * * * *
* * * * * * *
* * * * * * *
Material: Wood