继承和虚方法

继承、虚方法、override、reintroduce

类的继承的例子

Object Pascal 支持继承与虚方法。 下例中 TDog 继承自 TAnimal

TDog 是子类(派生类) TAnimal 是父类(祖先类)

program AnimalDemo;
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
{$codepage utf8}
uses SysUtils;

type
  // 动物父类
  TAnimal = class
    procedure Cry; virtual; // 虚方法:动物叫
  end; // 类定义结束,只有 end;

  // 狗子类,继承动物并重写叫声
  TDog = class(TAnimal)
    procedure Cry; override;
  end;

procedure TAnimal.Cry;
begin
  WriteLn('动物发出叫声');
end;

procedure TDog.Cry;
begin
  WriteLn('汪汪汪');
end;

var
  Pet: TAnimal;
begin
  // 父类实例
  Pet := TAnimal.Create;
  try
    Pet.Cry;
  finally
    FreeAndNil(Pet);
  end;

  // 子类实例,父类变量接收,多态生效
  Pet := TDog.Create;
  try
    Pet.Cry;
  finally
    FreeAndNil(Pet);
  end;
end.Code language: JavaScript (javascript)

执行结果

D:\fpcdemo>fpc mydemo.dpr
Free Pascal Compiler version 3.2.2 [2021/05/15] for i386
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling mydemo.dpr
Linking mydemo.exe
45 lines compiled, 0.1 sec, 68544 bytes code, 4260 bytes data

D:\fpcdemo>mydemo
动物发出叫声
汪汪汪Code language: CSS (css)

FreeAndNil

安全释放对象,两步合一:

  1. 调用对象 Free 销毁内存;
  2. 把变量置为 nil,防止野指针。

上面这句代码是一个子类的TDog对象存储在TAnimal Pet的变量里面,但是下面用Pet去调用Cry的时候,指向的是TDog里面的Cry,不是TAnimal里面的Cry,这里就是多态。

  • Cry; virtual 父类标记为虚方法,开启运行时多态;
  • 子类用 override 重写 Cry
  • 变量声明是 TAnimal,但实际对象是 TDog,自动执行狗的叫声。

标记 virtual 的方法:编译器运行时根据对象实际类型匹配对应方法实现。

如果删掉 virtualoverride

两次调用都会执行父类方法

上面是删除了virtualoverride

输出的都是TAnimal中的

编译器只认变量声明类型 TMyClass,无视对象实际类型。

  • 普通方法默认非虚,加 virtual 才是虚方法;
  • 子类重写父类虚方法必须写 override,否则编译器警告;
  • 若想屏蔽父类同名虚方法、不做重写,使用 reintroduce(不推荐,易造成混淆)相当于 C#中的new

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注