接口实际就相当于C++中的多重继承。只不过接口类不存在任何数据字段,只存在方法,这也是它被称为接口的原因。至于为什么DELPHI用接口代替多重继承,就是避免了基类中存在数据字段时的缺点(在EFFECTIVE C++中有描述。)

解决方案 »

  1.   

    接口是一个很好的概念。在Delphi中一个类可以完成多个接口。
    在这方面,Java,C#和Delphi具有同样的特性。
      

  2.   

    D5DG中的Form Wizard就是很好的一例。unit ABWizard;interfaceuses Windows, Classes, ToolsAPI;type
      TAppBarWizard = class(TNotifierObject, IOTAWizard, IOTARepositoryWizard,
        IOTAFormWizard, IOTACreator, IOTAModuleCreator)
      private
        FUnitIdent: string;
        FClassName: string;
        FFileName: string;
      protected
        // IOTAWizard methods
        function GetIDString: string;
        function GetName: string;
        function GetState: TWizardState;
        procedure Execute;
        // IOTARepositoryWizard / IOTAFormWizard methods
        function GetAuthor: string;
        function GetComment: string;
        function GetPage: string;
        function GetGlyph: Cardinal;
        // IOTACreator methods
        function GetCreatorType: string;
        function GetExisting: Boolean;
        function GetFileSystem: string;
        function GetOwner: IOTAModule;
        function GetUnnamed: Boolean;
        // IOTAModuleCreator methods
        function GetAncestorName: string;
        function GetImplFileName: string;
        function GetIntfFileName: string;
        function GetFormName: string;
        function GetMainForm: Boolean;
        function GetShowForm: Boolean;
        function GetShowSource: Boolean;
        function NewFormFile(const FormIdent, AncestorIdent: string): IOTAFile;
        function NewImplSource(const ModuleIdent, FormIdent,
          AncestorIdent: string): IOTAFile;
        function NewIntfSource(const ModuleIdent, FormIdent,
          AncestorIdent: string): IOTAFile;
        procedure FormCreated(const FormEditor: IOTAFormEditor);
      end;implementationuses Forms, AppBars, SysUtils, DesignIntf;{$R CodeGen.res}type
      TBaseFile = class(TInterfacedObject)
      private
        FModuleName: string;
        FFormName: string;
        FAncestorName: string;
      public
        constructor Create(const ModuleName, FormName, AncestorName: string);
      end;  TUnitFile = class(TBaseFile, IOTAFile)
      protected
        function GetSource: string;
        function GetAge: TDateTime;
      end;  TFormFile = class(TBaseFile, IOTAFile)
      protected
        function GetSource: string;
        function GetAge: TDateTime;
      end;{ TBaseFile }constructor TBaseFile.Create(const ModuleName, FormName,
      AncestorName: string);
    begin
      inherited Create;
      FModuleName := ModuleName;
      FFormName := FormName;
      FAncestorName := AncestorName;
    end;{ TUnitFile }function TUnitFile.GetSource: string;
    var
      Text: string;
      ResInstance: THandle;
      HRes: HRSRC;
    begin
      ResInstance := FindResourceHInstance(HInstance);
      HRes := FindResource(ResInstance, 'CODEGEN', RT_RCDATA);
      Text := PChar(LockResource(LoadResource(ResInstance, HRes)));
      SetLength(Text, SizeOfResource(ResInstance, HRes));
      Result := Format(Text, [FModuleName, FFormName, FAncestorName]);
    end;function TUnitFile.GetAge: TDateTime;
    begin
      Result := -1;
    end;{ TFormFile }function TFormFile.GetSource: string;
    const
      FormText =
        'object %0:s: T%0:s'#13#10'end';
    begin
      Result := Format(FormText, [FFormName]);
    end;function TFormFile.GetAge: TDateTime;
    begin
      Result := -1;
    end;{ TAppBarWizard }{ TAppBarWizard.IOTAWizard }function TAppBarWizard.GetIDString: string;
    begin
      Result := 'DDG.AppBarWizard';
    end;function TAppBarWizard.GetName: string;
    begin
      Result := 'DDG AppBar Wizard';
    end;function TAppBarWizard.GetState: TWizardState;
    begin
      Result := [wsEnabled];
    end;procedure TAppBarWizard.Execute;
    begin
      (BorlandIDEServices as IOTAModuleServices).GetNewModuleAndClassName(
        'AppBar', FUnitIdent, FClassName, FFileName);
      (BorlandIDEServices as IOTAModuleServices).CreateModule(Self);
    end;{ TAppBarWizard.IOTARepositoryWizard / TAppBarWizard.IOTAFormWizard }function TAppBarWizard.GetGlyph: Cardinal;
    begin
      Result := 0;  // use standard icon
    end;function TAppBarWizard.GetPage: string;
    begin
      Result := 'DDG';
    end;function TAppBarWizard.GetAuthor: string;
    begin
      Result := 'Delphi Developer''s Guide';
    end;function TAppBarWizard.GetComment: string;
    begin
      Result := 'Creates a new AppBar form.'
    end;{ TAppBarWizard.IOTACreator }function TAppBarWizard.GetCreatorType: string;
    begin
      Result := '';
    end;function TAppBarWizard.GetExisting: Boolean;
    begin
      Result := False;
    end;function TAppBarWizard.GetFileSystem: string;
    begin
      Result := '';
    end;function TAppBarWizard.GetOwner: IOTAModule;
    var
      I: Integer;
      ModServ: IOTAModuleServices;
      Module: IOTAModule;
      ProjGrp: IOTAProjectGroup;
    begin
      Result := nil;
      ModServ := BorlandIDEServices as IOTAModuleServices;
      for I := 0 to ModServ.ModuleCount - 1 do
      begin
        Module := ModSErv.Modules[I];
        // find current project group
        if CompareText(ExtractFileExt(Module.FileName), '.bpg') = 0 then
          if Module.QueryInterface(IOTAProjectGroup, ProjGrp) = S_OK then
          begin
            // return active project of group
            Result := ProjGrp.GetActiveProject;
            Exit;
          end;
      end;
    end;function TAppBarWizard.GetUnnamed: Boolean;
    begin
      Result := True;
    end;{ TAppBarWizard.IOTAModuleCreator }function TAppBarWizard.GetAncestorName: string;
    begin
      Result := 'TAppBar';
    end;function TAppBarWizard.GetImplFileName: string;
    var
      CurrDir: array[0..MAX_PATH] of char;
    begin
      // Note: full path name required!
      GetCurrentDirectory(SizeOf(CurrDir), CurrDir);
      Result := Format('%s\%s.pas', [CurrDir, FUnitIdent, '.pas']);
    end;function TAppBarWizard.GetIntfFileName: string;
    begin
      Result := '';
    end;function TAppBarWizard.GetFormName: string;
    begin
      Result := FClassName;
    end;function TAppBarWizard.GetMainForm: Boolean;
    begin
      Result := False;
    end;function TAppBarWizard.GetShowForm: Boolean;
    begin
      Result := True;
    end;function TAppBarWizard.GetShowSource: Boolean;
    begin
      Result := True;
    end;function TAppBarWizard.NewFormFile(const FormIdent,
      AncestorIdent: string): IOTAFile;
    begin
      Result := TFormFile.Create('', FormIdent, AncestorIdent);
    end;function TAppBarWizard.NewImplSource(const ModuleIdent, FormIdent,
      AncestorIdent: string): IOTAFile;
    begin
      Result := TUnitFile.Create(ModuleIdent, FormIdent, AncestorIdent);
    end;function TAppBarWizard.NewIntfSource(const ModuleIdent, FormIdent,
      AncestorIdent: string): IOTAFile;
    begin
      Result := nil;
    end;procedure TAppBarWizard.FormCreated(const FormEditor: IOTAFormEditor);
    begin
      // do nothing
    end;end.
      

  3.   

    chechy(我爱洁洁) (  ) 兄:
        你给我的例子过于复杂;我不知道通过接口类TAppBarWizard,
    得到了那些方法???
      

  4.   

    老兄啊~书上讲接口的时候应该有例子的吧?不行的话,看看这里:http://www.sunistudio.com/asp/sunidoc.asp?act=-2&article=314OK ?
      

  5.   

    上述例子中可以如此:
    var
      a: IOTARepositoryWizard;
      b: IOTACreator;
      c: TAppBarWizard;  c := TAppBarWizard.Create;
      b := c;
      a := c;
      // a = b as IOTARepositoryWizard;
      ...
      

  6.   

    To  LoveSick(黯然销魂客) ,不同意你的观点
      

  7.   

    有一本书叫Delphi COM Programming,中文也有译本。看看你就明白了。
      

  8.   

    如果你用DELPHI6,你可以看Multiple Inheritence这个例子。
    我对接口的理解是:接口定义了一些方法(但没有实现)。
    继承一个接口的类必须实现接口中定义的方法。
    可以说你继承一个接口什么都没得到,还要实现接口定义的方法。
      

  9.   

    这种所谓的多重继承只是继承了特征,并不继承实现。如果真的要实现多个基类的功能,建议用聚合。另外,比如,A、B两个基类,如果用到了A的全部特性,而只用到了B的部分特性,为了子类C的职责明确,建议在类C中聚合A以及一个根据B设计的Adapter类。这时用多重继承可能会造成管理上的混乱。
      

  10.   

    INeedCa(缺钙):
       现在我的理解也是这样的,实现在本类中,那这样的话,接口有什么用!
      

  11.   

    INeedCa(缺钙):
       哪里可以找到关于“聚合”的资料!
      

  12.   

    也许你是想看这样的例子?
    type
      TAncestorA = class(TInterfacedObject, IAncestorA)
      protected
        procedure IAncestorAFunc;  //声明在IAncestorA中的方法,这里提供实现
        ……
      end;  TAncestorB = class(TIntefacedObject, IAncestorB)
      protected
        procedure IAncestorBFunc;  //声明在IAncestorB中的方法,这里提供实现
        ……
      end;  TMyClass = class(TInterfacedObject, IAncestorA, IAncestorB)
      private
        AncestorAObj: IAncestorA;
        AncestorBObj: IAncestorB;
      public
        constructor Create; override;
        destructor Destroy; override;
        procedure IAncestorAFunc;
        procedure IAncestorBFunc;
      end;Implementconstructor TMyClass.Create;
    begin
      inherited;
      AncestorAObj := CreateComObj(……);  //创建TAncestorA的实例
      AncestorBObj := CreateComObj(……);  //创建TAncestorB的实例
    end;destructor TMyClass.Destroy;
    begin
      AncestorAObj := nil;
      AncestorBObj := nil;
      inherited;
    end;procedure TMyClass.IAncestorAFunc;
    begin
      AncestorAObj.IAncestorAFunc;
    end;procedure TMyClass.IAncestorBFunc;
    begin
      AncestorBObj.IAncestorBFunc;
    end;
      

  13.   

    使用接口来得到多继承,其实是用接口引用举例如下
    IWalker = interface
        ['{6783F83D-A00C-4A25-B3D6-337A42038974}']
        function Work: string;
        function Run: string;
        function GetPos: integer;
        procedure SetPos(Value: integer);
        property Position: integer read GetPos write SetPos;
      end;  IJumper = interface
        ['{414BEF73-7543-4A15-81DC-F8BB91019AFC}']
        function Jump: string;
        function walk: string;
        function GetPos: integer;
        procedure SetPos(Value: integer);
        property Position: integer read GetPos write SetPos;
      end;
    TJumpImpl = class(TInterfacedObject, IJumper)

    end;TAthlete = class(TInterfacedObject, IWalker, IJumper)
      private
        fJumpImpl: TJumpImpl;
      public
        constructor Create;
        function Run: string; virtual;
        function Walk1: string; virtual;
        function IWalker.Walk = Walk1;
        function GetPos: integer;
        procedure SetPos(Value: integer);
        property Jumper: TJumpImpl read fJumpImpl implements IJumper;
      end;constructor TAthlete.Create;
    begin
      fJumpImpl := TJumpImpl.Create;
    end;这样,就实现了多继承
      

  14.   

    ChipHead(满脑袋芯片和程序的人) 提供的就是一个聚合的例子,TMyClass中聚合了IA、IB两个对象,从而实现了这两个类的功能。这种聚合的好处在于,三个类是分别维护的,你甚至可以在运行的时候动态的给IA、IB赋不同的实现者(TA1、TA2...、TB1、TB2...),以适应不同的环境,就象给赛车上不同的轮胎以适应不同的路面一样。
    有时候IA、IB的功能会超过了你需要的功能,比如IAncestorFunc9根本不是TMyClass中应该具有的功能,如果将这个方法体现在TMyClass中,反而会引起TMyClass概念模糊,职责不清。这时用聚合的方式可以很容易的对成员的功能进行裁减。
    或者对于TMyClass的使用者来说,需要更加明确的功能定义。比如IA提供了CopyFileTo,DeleteFile,IB提供了CopyDir,DeleteDir,而TMyClass作为一个文件管理器,可能需要提供Copy、Delete、Cut功能,用聚合的优点就更加体现出来了。