【问题标题】:How to implement multiple inheritance in delphi?delphi如何实现多重继承?
【发布时间】:2009-08-14 05:18:23
【问题描述】:

我正在对一个旧库进行全面重写,但我不确定如何处理这种情况(为了便于理解,大家都欢迎自行车类比):

我有以下课程:

  • TBike - 自行车本身
  • TBikeWheel - 自行车的轮子之一
  • TBikeWheelFrontTBikeWheelBack,都继承自 TBikeWheel,然后在其之上实现他们需要的特定内容

这很简单,但现在我决定创建多种自行车,每辆自行车都有自己的车轮 - 它们与普通的前/后轮做相同的事情,加上针对该自行车的特定功能。

  • TBikeXYZ - 继承自 TBike
  • TBikeWheelXYZ - 继承自 TBikeWheel

这是我的问题:TBikeWheelFrontXYZ 应该继承自 TBikeWheelXYZ(获取 XYZ 轮的具体方法),但它也应该继承自 TBikeWheelFront(获取前轮的具体方法) .

我的问题是,我怎样才能以一种不这样的方式实现它:

  1. 感觉像个黑客
  2. 强迫我多次重写相同的代码

【问题讨论】:

    标签: delphi multiple-inheritance


    【解决方案1】:

    Delphi 不支持多重继承。但是类可以支持/实现多个接口,你可以委托接口实现,所以你可以模拟多重继承。

    【讨论】:

      【解决方案2】:

      使用接口。像这样的东西(根据你的描述,在我的脑海中......)

      type
      
        IBikeWheel = interface
          ...
        end;
      
        IXYZ = interface
          ...
        end;
      
        IFrontWheel = interface(IBikeWheel)
          ...
        end;
      
      
        TBike = class
          ...
        end;
      
        TBikeWheel = class(TObject, IBikeWheel);
      
        TBikeWheelXYZ = class(TBikeWheel, IXYZ);
      
        TBikeFrontWheelXYZ = class(TBikeWheelXYZ, IFrontWheel);
      

      然后为执行旧(可能是 C/C++)库中的相应类所做的接口实现类,并在相应类的构造函数中实例化它们。

      【讨论】:

        【解决方案3】:

        使用多态将每个“事物”实现为自身的对象层次结构,然后依次将对象属性添加到该对象。因此,创建一个车轮层次结构和一个自行车层次结构。然后将轮子添加到自行车作为祖先自行车对象中的字段。见下文。

          TBikeWheel = class
          TBikeWheelXYZ = class( TBikeWheel ) 
        
          TBike = class
            FFrontWheel : TBikeWheel;
            property FrontWheel : TBikeWheel
              read FrontWhell  
        
          TBikeABC = class( TBike)
            constructor Create;
          end;
        
          constructor TBikeABC.Create;
          begin
            inherited;
            FFrontWheel := TBikeWheel.Create;
          end;
        
          TBikeXYZ = class( TBike)
            constructor Create;
          end;
        
          constructor TBikeXYZ.Create;
          begin
            inherited;
            FFrontWheel := TBikeWheelXYZ.Create;
          end;
        

        【讨论】:

        • +1,包容通常比继承更好地模拟现实。
        【解决方案4】:

        Brian Frost 建议的变体:

          TBikeWheel = class
          TBikeWheelXYZ = class( TBikeWheel ) 
        
          TBike = class
            FFrontWheel : TBikeWheel;
          protected
            function CreateWheel: TBikeWheel; virtual;
          public
            property FrontWheel : TBikeWheel
              read FrontWheel  
          end;
        
          TBikeABC = class( TBike)
          protected
            function CreateWheel: TBikeWheel; override;
          end;
        
          function TBikeABC.CreateWheel: TBikeWheel;
          begin
            result := TBikeWheel.Create;
          end;
        
          TBikeXYZ = class( TBike)
          protected
            function CreateWheel: TBikeWheel; override;
          end;
        
          function TBikeXYZ.CreateWheel: TBikeWheel;
          begin
            result := TBikeWheelXYZ.Create;
          end;
        

        【讨论】:

          【解决方案5】:

          基本上 - 你不能。 Delphi 不支持多重继承。

          所以离开这个困境,问题是:你能不能重构那个库,让你可以摆脱使用接口的方式?多重继承主要是关于函数和方法吗?如果是这样 - 使用接口。 Delphi 可以在一个类上支持多个接口。

          如果多重继承更多的是继承类中的实际功能,那么恐怕您正在考虑进行更大规模的重构。您需要找到一种方法来分解这些功能依赖关系,使其可以从单个基类继承,可能还会引入一些额外的接口。

          抱歉,我无法提供简单的答案 - 这就是现实。

          马克

          【讨论】:

            【解决方案6】:

            您可以尝试从 TBikeWheelFront 中提取一个接口,例如 IFrontWheel,使其成为 TBikeWheel 的子类,但实现了 IFrontWheel。然后 TBikeWheelXYZ 继承自 TBikeWheel 和 TBikeWheelFrontXYZ 继承自 TBikeWheelXYZ 并实现 IFrontWheel。

            然后您可以定义一个类 TFrontwheel 并为其提供与接口相同的方法,但现在您实现它们。然后 TBikeWheelFront 和 TBikeWheelXYZ 得到一个 TFrontwheel 类型的私有成员,它们的 IFrontWheel 实现简单地委托给私有成员方法。

            这样你就没有双重实现了。

            【讨论】:

              【解决方案7】:

              较新版本的 Delphi 的另一个替代方法是在组合模型中利用泛型。这在多个基类(本例中为TBarATBarB)不可访问以进行修改(即:框架或库类)的情况下特别有用。例如(注意,为简洁起见,此处省略了TFoo<T> 中必要的destructor):

              program Project1;
              
              uses SysUtils;
              
              {$APPTYPE CONSOLE}
              
              type    
                TFooAncestor  = class
                  procedure HiThere; virtual; abstract;
                end;
                TBarA = class(TFooAncestor)
                  procedure HiThere; override;
                end;
                TBarB = class(TFooAncestor)
                  procedure HiThere; override;
                end;
                TFoo<T: TFooAncestor, constructor> = class
                  private
                    FFooAncestor: T;
                  public
                    constructor Create;
                    property SomeBar : T read FFooAncestor write FFooAncestor;
                end;
              
              procedure TBarA.HiThere;
              begin
                WriteLn('Hi from A');
              end;
              
              procedure TBarB.HiThere;
              begin
                WriteLn('Hi from B');
              end;
              
              constructor TFoo<T>.Create;
              begin
                inherited;
                FFooAncestor := T.Create;
              end;
              
              var
                FooA : TFoo<TBarA>;
                FooB : TFoo<TBarB>;
              begin
                FooA := TFoo<TBarA>.Create;
                FooB := TFoo<TBarB>.Create;
                FooA.SomeBar.HiThere;
                FooB.SomeBar.HiThere;
                ReadLn;
              end.
              

              【讨论】:

                【解决方案8】:

                如果不想多次重复代码,想要解耦代码,可以试试这种方式。

                type
                   TForm1 = class(TForm)
                    btnTest: TButton;
                    procedure btnTestClick(Sender: TObject);
                   private
                      { Private declarations }
                   public
                      { Public declarations }
                   end;
                
                   TBike = class
                   end;
                
                   IBikeWheel = interface
                      procedure DoBikeWheel;
                   end;
                
                   TBikeWheel = class(TInterfacedObject, IBikeWheel)
                   public
                      procedure DoBikeWheel;
                   end;
                
                   IBikeWheelFront = interface
                      procedure DoBikeWheelFront;
                   end;
                
                   TBikeWheelFront = class(TInterfacedObject, IBikeWheelFront)
                   public
                      procedure DoBikeWheelFront;
                   end;
                
                   IBikeWheelBack = interface
                   end;
                
                   TBikeWheelBack = class(TInterfacedObject, IBikeWheelBack)
                   end;
                
                   TBikeWheelFrontXYZ = class(TInterfacedObject, IBikeWheel, IBikeWheelFront)
                   private
                      FIBikeWheel: IBikeWheel;
                      FBikeWheelFront: IBikeWheelFront;
                   public
                      constructor Create();
                      property BikeWheel: IBikeWheel read FIBikeWheel implements IBikeWheel;
                      property BikeWheelFront: IBikeWheelFront read FBikeWheelFront implements IBikeWheelFront;
                   end;
                
                var
                   Form1: TForm1;
                
                implementation
                
                {$R *.DFM}
                
                { TBikeWheel }
                
                procedure TBikeWheel.DoBikeWheel;
                begin
                   ShowMessage('TBikeWheel.DoBikeWheel');
                end;
                
                { TBikeWheelFrontXYZ }
                
                constructor TBikeWheelFrontXYZ.Create;
                begin
                   inherited Create;
                   Self.FIBikeWheel := TBikeWheel.Create;
                   Self.FBikeWheelFront := TBikeWheelFront.Create;
                end;
                
                { TBikeWheelFront }
                
                procedure TBikeWheelFront.DoBikeWheelFront;
                begin
                   ShowMessage('TBikeWheelFront.DoBikeWheelFront');
                end;
                
                procedure TForm1.btnTestClick(Sender: TObject);
                var
                   bikeWhell: TBikeWheelFrontXYZ;
                begin
                   bikeWhell := nil;
                   try
                      try
                         bikeWhell := TBikeWheelFrontXYZ.Create;
                         IBikeWheelFront(bikeWhell).DoBikeWheelFront;
                         IBikeWheel(bikeWhell).DoBikeWheel;
                      except
                         on E: Exception do
                         begin
                            raise;
                         end;
                      end;
                   finally
                      if Assigned(bikeWhell) then FreeAndNil(bikeWhell);
                   end;                                          
                end;
                

                【讨论】:

                  【解决方案9】:

                  抱歉,Delphi 不支持多重继承。

                  【讨论】:

                    【解决方案10】:

                    我想建议以下步骤:

                    1. TBikeWheelXYZTBikeWheelFront 继承TBikeWheelFrontXYZ 类(因为在Delphi 中多重继承是不可能的,如上面的答案所述)。

                    2. TBikeWheelXYZTBikeWheelFront 的父类之一转换为TBikeWheel 类的类助手。

                    3. 将类助手单元添加到声明TBikeWheelFrontXYZ 类的单元中。

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2011-11-21
                      • 2020-08-09
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-07-13
                      • 2019-05-27
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多