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:

[pascal][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;[/pascal]

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!