PDA

View Full Version : Abstract Error with TStrings object



WILL
15-07-2003, 10:18 PM
I've been trying to use TStrings in a simple object as a decendant of TObject. However I keep getting abstract errors as a result of it's envolvement in the new class. I've been all over the place with the help files(Delphi 5 Standard) and found nothing on how to properly declare whatever I need to as a abstract method, priority or whatever. If someone has experiance with the TStrings class, can you give me a small coded example? Thanks. :)

Avatar
16-07-2003, 05:39 AM
Hi.

A TStrings could be used like that :



var
Str : TStrings;

procedure LoadFile(filename : String);
Begin
Str := TStringList.Create;
Str.Lines.LoadFromFile(Filename);
end;

procedure Addline(Line : String);
Begin
Str.Lines.add(Line);
end;



I wonder if your abstract exception doesn't come with the creation ... If not could you post the part of the code which is generating that exception ?

Bye
Avatar

ra001
16-07-2003, 05:40 AM
Hi.
You need using TStringList



Var
Ts :TStrings;
begin
Ts := TstringList.Create;
...
Ts.Free;
end;

Avatar
16-07-2003, 05:47 AM
oops :) Forgot to free ^^. Anyway I do believe that the exception comes with the creation .

WILL
16-07-2003, 08:26 AM
Hmm... thats interesting. I used TStrings.Create as the constructor. I'll give that a try. Odd... normally you'd use the same class objct to create the object you made. :?

Well.. thanks guys, I'll let you know if it works.

ra001
16-07-2003, 09:10 AM
Hmm... thats interesting. I used TStrings.Create as the constructor. I'll give that a try. Odd... normally you'd use the same class objct to create the object you made. :?



That is werry many possibles used some class what is develop from parent



type
TMyParent = class
end;

TMyInteger = class(TMyParent)
Procedure ShowMe;
end;

TMyString = class(TMyParent)
procedure ShowMe;
end;

TForm1 = class(TForm)
MyValue : TMyParent;
constructor create(Aowner : TComponent);override;
end;

procedure TMyInteger.ShowMe;
begin
ShowMessage('Hello Integer');
end;


procedure TMyString.ShowMe;
begin
ShowMessage('Its string');
end;

constructor TForm1.Create(Aowner : TComponent);
begin
inherited;
if ParamStr(1) = 'integer')
then MyValue := TMyInteger.Create
else MyValue := TMyString.Create;
end;

procedure TForm1.OnClick;
begin
MyValue.ShowMe;
end;

ra001
16-07-2003, 09:51 AM
Sorry error in my sample
Type definition is in that format



TMyParent = class
procedure ShowMe;virtual;
end;

TMyInteger = class(TMyParent)
Procedure ShowMe;override;
end;

TMyString = class(TMyParent)
procedure ShowMe;override;
end;

WILL
17-07-2003, 12:38 AM
Holy cow it worked. :? Could it be because TStrings isn't supposed to be used directly? I failed to understand why it functions this way. I would never get the error until it had done whatever my method containing the comands to the TStrings object was finished and then die at whatever the next method of function was from any object that accessed memory. Very odd behaviour...

Anyhoo, Thanks guys! :)

Maja
17-07-2003, 10:07 PM
TStrings contains abstract or, in C++ terminology, pure virtual methods and should not be directly instantiated.

delphi help..

Alimonster
19-07-2003, 10:57 AM
Yep, as Maja said: it's an abstract class. In fact, most Delphi versions warn you about instantiating a class that is abstract.

An abstract class provides "placeholder" functionality that isn't implemented in that class. The idea is that you'll descend classes from this abstract class which implement the functionality. If the descending classes don't implement all of the abstract classes then they too are abstract. Make sense?

I believe that it's usually okay to create abstract classes if you don't invoke the abstract methods -- but this is very risky (and might not be the case, since I can't say I've ever tried ;)).

Now, you've bumped into polymorphism here. The descending classes are a type of the base class (the term used is "is a", as in "a Rolls-Royce is a car"). Polymorphism can be used in the abstract class' case: you declare a base class object and can then make it into a sub-class if required. Some example code:

[background=#FFFFFF][comment=#0000FF][normal=#000000][number=#C00000][reserved=#000000][string=#00C000]type
TBase = class
public
procedure Hello; virtual; abstract; // not implemented in TBase
end;

TSubA = class(TBase)
public
procedure Hello; override; // implements this!
end;

TSubB = class(TBase)
public
procedure Hello; override; // implements this too!
end;

procedure TSubA.Hello;
begin
ShowMessage('Subclass A says hello');
end;

procedure TSubB.Hello;
begin
ShowMessage('Subclass B says hello as well');
end;

//...

var
TheObj: TBase; // note: the base class!
begin
TheObj := TSubA.Create; // try TSubB.Create as well and notice the correct behaviour
TheObj.Hello;
TheObj.Free;
end;

Notice that the variable there is declared as the base class, but is created as a subclass. This is possible because of polymorphism. Note that abstract classes must be virtual. If you create a class as above then the method has to be routed to the correct subclass, as usual for virtual things. If it wasn't, of course, then we'd end up calling TBase.Hello instead of TSubA.Hello at the appropriate time. You can't say "TheObj := TBase.Create" in the above example because you'd be calling an abstract function, which would be no good.

You can use abstract virtual functions to create something akin to interfaces (when used as a base class).

Anyway, the point: TStrings is a base class that's abstract. It explodes when you attempt to call one of its abstract methods, since they don't actually exist in that class at all! I think, if memory serves, that this is a run-time error, but maybe not. Therefore, you create a sub-class which does implement the behaviour. You can still declare the variable of type TStrings, since (e.g.) a TStringList is a TStrings object, but with extra gubbins. The only problem is that non-virtual methods will be called against the TStrings aspect of the object, rather than its created type. This ought not to be a problem though -- non virtual functions in a base class are typically not required to be virtual, or call virtual functions behind the scenes to do the dirty work (c.f. TObject.Free versus TObject.Destroy).

Also: Hi everyone, I'm back! I've moved into a new flat with some other people and now have broadband. Yay!

WILL
19-07-2003, 11:11 AM
Ok thanks. I think I understand a little better now. This isn't very clearly explained in the Help files. It's enough for me to know now anyhow.