[OO/Delphi] Snap het even niet...

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 00:20
Ik ben momenteel bezig met een programma waarin diverse soorten variabelen aangemaakt kunnen worden. Deze worden in een grote lijst bewaard. Als basis heb ik het volgende object:

(overige code weggeknipt)
Delphi:
1
2
3
4
5
6
7
8
  TObj=class
    Naam:string;
    Soort:Integer;
  public
    function IsFunction(Func:string):boolean;
   private
    function IsOwnFunction(Func: string): boolean; 
  end;


Hier zijn nog twee objecten vanaf geleid:
Delphi:
1
2
3
4
  Type1=class(TObj)
   private
    function IsOwnFunction(Func: string): boolean; 
  end;


Delphi:
1
2
3
4
  Type2=class(TObj)
   private
    function IsOwnFunction(Func: string): boolean; 
  end;


Nu heb ik ook een standaard ObjectList:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  TObjList=class(TObjectList)
    function IsFunction(Func:string):boolean; overload;
    function IsFunction(Index: Integer; Rest: string): boolean; overload;
   public
    function IndexOf(Naam:string):Integer;
  end;

function TObjList.IsFunction(Func: string): boolean;
var
  Index: Integer;
  Basis:string;
  Rest:string;
begin
  Basis:=Copy(Func,1,Pos('.',Func)-1);
  Rest:=Copy(Func,Pos('.',Func)+1, 1000);

  Index:=Indexof(Basis); //Code van IndexOf heb ik weggelaten

  Result:=IsFunction(Index, Rest);
end;

function TObjList.IsFunction(Index: Integer; Rest: string): boolean;
begin
  Result:=False;
  if Index>-1 then
    case TObj(Items[Index]).Soort of
      1:Result:=Type1(Items[Index]).IsFunction(Rest);
      2:Result:=Type2(items[Index]).IsFunction(Rest);
    end;
end;


Als voorbeeld voeg ik nu 2 objecten toevoeg aan de lijst:
Delphi:
1
2
objlist.add(type1.create('Dummy'));
objlist.add(type2.create('Test'));


In de constructor zorg ik dat de soort-variabele wordt gevuld met een 1 of 2. (In de werkelijke code is dit natuurlijk een enumerator).


Nu verwacht ik dat als ik aan de objlist vraag IsFunction('Test.Test2'), dat objlist gaat naar
TObjList.IsFunction en daar achter komt dat Test de naam is van van object nummer 2 en daarna de functie IsFunction(2,'Test2') uitvoert.
Dit gaat goed.

Nu komt de code terecht in TObj.IsFunction(), want die is in Type1 en Type2 niet opnieuw gedefinieerd.
Deze code is als volgt:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
function TObj.IsFunction(Func: string): boolean;
var
  Punt:Integer;
begin
  Punt:=Pos('.',Func);
  Result:=false;

  if Punt=0 then
  begin
    result:=IsOwnFunction(Func);
  end;
  // De else is voor het voorbeeld niet belangrijk
end;


Hij komt er nu achter dat er geen punt inzit en dus moet uitzoeken of het een eigen functie is binnen het object. En nu komt mijn vraag, waarom springt de code nu naar TObj.IsOwnFunction('Test2') en niet naar Type2.IsOwnFunction('Test2'), terwijl ik middels de 'case of' het exacte type specificeer?

En daarnaast nog een tweede vraag, hoe kan ik voorkomen dat ik elke keer alle types moet opgeven, en dat het programma zelf uitzoekt wat voor type dit is?
Delphi:
1
2
3
4
    case TObj(Items[Index]).Soort of
      1:Result:=Type1(Items[Index]).IsFunction(Rest);
      2:Result:=Type2(items[Index]).IsFunction(Rest);
    end;


Het heeft denk ik te maken met de code woorden abstract, virtual, dynamic, override, maar ik kan nergens een soortgelijke situatie vinden

PS, ik heb hem in SEA gezet omdat ik denk dat dit iets algemeens is. Als hij naar PRG moet, zie ik dat vanzelf.

[ Voor 1% gewijzigd door jvdmeer op 26-10-2007 23:28 . Reden: Sluittags verbeterd ]


Acties:
  • 0 Henk 'm!

  • Xiphalon
  • Registratie: Juni 2001
  • Laatst online: 12-09 14:03
Je moet in de base classe inderdaad de methoden die je wil overriden markeren met virtual.
Virtual zorgt ervoor dat er pas run-time gekeken wordt van welke classe de betreffende methode wordt aangeroepen. Dit in plaats van compile-time, dus dat de compiler het voor je uitzoekt, dan krijg je gewoon een call naar de base classe.

Mocht de base classe geen implementatie hebben van de virtuele methode, moet je hem abstract markeren, dan kan je de implementatie achterwege laten. Let er wel op dat je de base classe dan niet meer kan instantieren.

Let er wel op dat als je een virtuele methode override'd, dat je die ook als zodanig moet markeren.

Krijg je trouwens geen waarschuwing bij het compileren van Type2?

[ Voor 10% gewijzigd door Xiphalon op 27-10-2007 11:53 . Reden: tis koud, typos ]


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 12-09 23:07
Jij moet eens kijken naar polymorphisme.

Maak een abstracte class, die een virtuele method heeft. Inherit je 2 classes van die abstracte class en override die virtuele method in je afgeleide classes.
Als je dan van iedere type een instantie creeërt, en deze in een list zet die objecten van het type van jouw abstracte class bijhouden, dan zal iedere keer de juiste method uitgevoerd worden.

Bv (in C#, Delphi is al te lang geleden om dit nog zomaar ff uit m'n vingers te rammelen)
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
abstract class  MyBaseType
{
     // Dit is de virtuele method
     public abstract void MyMethod();
}

class Class1 : MyAbstractType
{
     public override void MyMethod()
     {
           Console.WriteLine ("Class1");
     }
}

public class Class2 : MyAbstractType
{
     public override void MyMethod()
     {
           Console.WriteLine ("Class2");
     }
}

List<MyAbstractType> l = new List<MyAbstractType()>();

l.Add (new Class1());
l.Add (new Class2());

foreach( MyAbstractType t in l )
{
     t.MyMethod();
}


Wat is de bedoeling eigenlijk van die 'soort' member ? Je gaat die toch niet gebruiken om te weten van welk type een bepaalde instantie is ?
Als je goed werkt met polymorphisme heb je dit helemaal niet nodig; en als je at-runtime dan toch nog wilt weten van welk type een bepaald object is, dan heb je in Delphi toch nog altijd RTTI ?

[ Voor 7% gewijzigd door whoami op 27-10-2007 12:00 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 00:20
darkmage schreef op zaterdag 27 oktober 2007 @ 11:50:
[...]
Krijg je trouwens geen waarschuwing bij het compileren van Type2?
Yep, eentje over het hiden van de functie in de base-class
whoami schreef op zaterdag 27 oktober 2007 @ 11:59:
Wat is de bedoeling eigenlijk van die 'soort' member ? Je gaat die toch niet gebruiken om te weten van welk type een bepaalde instantie is ?
Ja, ik wist even geen betere manier. Dus inderdaad gebruik ik nu de 'soort'-member. Maar het liefst wil ik die er uit hebben. Dat was ook mijn 2e vraag in de TS:
jvdmeer schreef op vrijdag 26 oktober 2007 @ 22:59:
[...]
En daarnaast nog een tweede vraag, hoe kan ik voorkomen dat ik elke keer alle types moet opgeven, en dat het programma zelf uitzoekt wat voor type dit is?
Delphi:
1
2
3
4
    case TObj(Items[Index]).Soort of
      1:Result:=Type1(Items[Index]).IsFunction(Rest);
      2:Result:=Type2(items[Index]).IsFunction(Rest);
    end;
Ik ga de suggecties met abstract, virtual en override proberen.
Wat is nu nog het verschil tussen virtual en dynamic?

Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 12-09 23:07
Dynamic is iig een keyword dat ik in die context niet ken in andere talen.
Echter, blijkbaar is dit gewoon semantisch hetzelfde als virtual:
klik
Dynamic is semantically equivalent to Virtual. The former is optimised for memory, the latter for speed.

[ Voor 22% gewijzigd door whoami op 27-10-2007 23:07 ]

https://fgheysels.github.io/