-2

I'm an newbee concerning interfaces. I googled a lot but i can't figure out what to do in the following situation.

i created serveral interfaces, which use each other:

IPart = interface(IInterface)
  Function getName: string;
  procedure setName(aValue: string)
  property Name: string read getName write setname;
end;


IOfferLine= interface(iInterface)
  Function getPart: IPart;
  function getAmount: double;
  procedure setPart(aPart: IPart);
  procedure setAmount(value: double);
  property Amount: double read getAmount write setAmount;
  property Part: IPart read GetPart write setPart;
end;

IOffer= interface(iInterface)
  function getOffLines: tList<IOfferline>;
  procedure setOffLines(aList: tList<IOfferline>);
  property OffLines: tList<IOfferlines> read getOffLines write setOfflines;
end;

Now i want to implement those interface.

TPart = class(TInterfacedObject, IPart)
  private
    _Name: string;
    function getName: string;
    procedure setName(aValue: string);
  public
    property Name: string read getName write setName;
end;

TOfferLine = class(TInterfacedObject, IOfferLine)
  private
    _amount: double;
    _part: TPart;
    function getAmount: double;
    function getPart: tPart;
    procedure setAmount(aValue: double);
    procedure setPart(aPart: TPart);
  public
    property Amount: double read getAmount write setAmount;
    property Part: TPart read GetPart write SetPart;
  end;

TOffer = class(TInterfacedObject, IOffer)
  private
    _OfferLines: tList<TOfferline>;
    function getOffLines: tList<tOfferline>;
    procedure setOffLines(aList: tList<tOfferline>);
  public
    property offLines: tList<TOfferline> read getOffLines write setOffLines;
end;

I have added the implementation.

function TOfferLine.getPart: tPart;
begin
  result := _part;
end;

But i still get 'Missing implementation of interface method IOfferline.GetPart;'

And i Can't figure out why.

J...
  • 30,968
  • 6
  • 66
  • 143
Hanne
  • 39
  • 3
  • 1
    The code you show does not compile and is quite messy. This suggests a lack of clarity and attention to detail. There is also no clear and direct question here. I think you probably need to re-write this question with a lot more focus. – David Heffernan Aug 13 '15 at 09:04
  • @DavidHeffernan, i edited the question. could you explain why this code is messy? – Hanne Aug 13 '15 at 09:09
  • The code still does not compile. It is still indented in a hard to read manner. There is still no specific question. It looks like you are trying to run before you can walk. – David Heffernan Aug 13 '15 at 09:11
  • There is the `end` keyword missing in all your type declarations. – Wosi Aug 13 '15 at 09:15
  • _OfferLines: tList missing ; in the end... Can you provide the error text of compiler.. we are not wizards there.. – Z.B. Aug 13 '15 at 09:18
  • `procedure setName(aValue: string)` -- also missing ending `;` – Zam Aug 13 '15 at 09:20
  • 2
    Of course... your GetPart in interface is IPart and not TPart!! – Z.B. Aug 13 '15 at 09:23
  • @ZENsan: thx for your answer, so if i understand correctly I need to change the interface of the offerline? – Hanne Aug 13 '15 at 09:25
  • No you need to change the impl. to return IPart type and not TPart. – Z.B. Aug 13 '15 at 09:26
  • You are trying to run before you can walk. The extreme mess makes it very hard for you to read your own code. Work on improving your code hygiene. – David Heffernan Aug 13 '15 at 10:02
  • Your interfaces lack a GUID, this will prevent the execution of the `QueryInterface` method in many moments. I understand my comment may sound misterious to you, but @David Heffernan is right when he says your trying to run before you can walking. There is some fundamental background you are lacking, what makes things even harder for you. Take some time to read about it in this link: [Delphi Basics](http://www.delphibasics.co.uk/Article.asp?Name=Interface). – AlexSC Aug 13 '15 at 10:35
  • After you have a better understanding on Interfaces, I suggest you review you coding style and conventions. It's very clear that you have influences from other languages (maybe C++ of Java) considering the way you name your internal fields. For instance, in `TPart` a typical Delphi programmer would indent `private` in the same column as `TPart` and would not name the field as `_Name`, but `FName`. Take a look at this [blog post](http://edn.embarcadero.com/article/10280). – AlexSC Aug 13 '15 at 10:41

2 Answers2

2

I dont know what you are trying to to but if you didn't write you code so messy it would be easier to read. But thank God we have a Source formatter.

There are seval problems in you code:

First You have your property declared as property OffLines: TList<IOfferline**s**> while your interface is named IOfferline

Then TOfferline you have a method procedure setPart(aPart: TPart); that should be procedure setPart(aPart: IPart); because thats how you declared your interface. And all the other places where you Use TPart should be IPart.

And the same goes for TOffer

Here is a cleaned up version of your code :

unit Unit20;

interface
uses
  Generics.Collections;

type
  IPart = interface(IInterface)
    function getName: string;
    procedure setName(aValue: string);
    property Name: string read getName write setName;
  end;

  IOfferLine = interface(IInterface)
    function getPart: IPart;
    function getAmount: double;
    procedure setPart(aPart: IPart);
    procedure setAmount(value: double);
    property Amount: double read getAmount write setAmount;
    property Part: IPart read getPart write setPart;
  end;

  IOffer = interface(IInterface)
    function getOffLines: TList<IOfferLine>;
    procedure setOffLines(aList: TList<IOfferLine>);
    property OffLines: TList < IOfferLine > read getOffLines write setOffLines;
  end;

  TPart = class(TInterfacedObject, IPart)
  private
    _Name: string;
    function getName: string;
    procedure setName(aValue: string);
  public
    property Name: string read getName write setName;
  end;

  TOfferline = class(TInterfacedObject, IOfferLine)
  private
    _amount: double;
    _part: TPart;
    function getAmount: double;
    function getPart: IPart;
    procedure setAmount(aValue: double);
    procedure setPart(aPart: IPart);
  public
    property Amount: double read getAmount write setAmount;
    property Part: IPart read getPart write setPart;
  end;

  TOffer = class(TInterfacedObject, IOffer)
  private
    _OfferLines: TList<TOfferline>;
    function getOffLines: TList<IOfferLine>;
    procedure setOffLines(aList: TList<IOfferLine>);
  public
    property OffLines: TList < IOfferLine > read getOffLines write setOffLines;
  end;

implementation

{ TOfferline }

function TOfferline.getAmount: double;
begin

end;

function TOfferline.getPart: IPart;
begin

end;

procedure TOfferline.setAmount(aValue: double);
begin

end;

procedure TOfferline.setPart(aPart: IPart);
begin

end;

{ TOffer }

function TOffer.getOffLines: TList<IOfferLine>;
begin

end;

procedure TOffer.setOffLines(aList: TList<IOfferLine>);
begin

end;

{ TPart }

function TPart.getName: string;
begin

end;

procedure TPart.setName(aValue: string);
begin

end;

end.
Jens Borrisholt
  • 6,174
  • 1
  • 33
  • 67
  • 1
    By the way.. there is no need to define properties in the implementing classes as they will be anyway referenced via interface. It just enough to implement getters and setters. Delphi is smart enough to show only property in the autocomplete for interface variable. – Z.B. Aug 13 '15 at 12:29
  • You are absolutly rgiht. I didn't look into the code, I just made it compile :p – Jens Borrisholt Aug 13 '15 at 12:55
  • @ZENsan - that depends on whether your properties are exclusively referenced thru the interfaces. e.g. if your interfaced class is a base class it can be annoying to have to use get/set methods to make references to inherited properties in the derived class implementations. – Deltics Aug 13 '15 at 23:51
-1

The reason the compiler is saying that the implementation is missing is simply because the implementation is missing.

Your interface for IOfferLine declares this getPart method:

IOfferLine= interface(iInterface)
  ..
  function getPart: IPart;
  ..
end;

But your implementing class does not provide this method. The getPart method in your class is implemented to return an object reference, not an interface reference:

TOfferLine = class(TInterfacedObject, IOfferLine)
private
  ..
  function getPart: tPart;
  ..
end;

You need to ensure that your implementing class actually provides the members required by the interfaces that it implements, exactly and precisely:

TOfferLine = class(TInterfacedObject, IOfferLine)
private
  ..
  function getPart: IPart;
  ..
end;

function TOfferline.getPart: IPart;
begin
  result := _part as IPart;
end;

However, since the reference to the Part maintained by the OfferLine object (in the _part variable) is an object reference, then references to that object obtained using interfaces (via the getPart: IPart method) could result in that Part object being destroyed since the object reference in OfferLine is not counted (literally).

You can of course avoid this by making the Part reference held by OfferLine an interface reference itself, but whether this is valid is difficult to say with out a complete picture of your entire object model. If the lifetimes of your objects are ensured by some other mechanism not apparent from the question then it may not be an issue, but if it is not something that has been specifically considered thus far then it probably does need addressing.

Although it is possible to do safely, as a general rule mixing object references and interface references to the same objects is a recipe for problems.

Deltics
  • 22,162
  • 2
  • 42
  • 70