IMHO methods not marked "virtual" can also be overwritten.
Are you sure? Let's try the simple code I provided below. Lets see if you remove the 'virtual' on the base class, what will happen?
Confused.
Words become less confusing if you try them in code.
The base class is TAnimal
line #28.
Here is how should to test the code:
- Run the code and see will happen.
- Remove the 'virtual' in the base class line #30. Run it and see what will happen.
- Undo the step #2 and remove those 'override' on both line #39 and line #46. Run it and see what will happen.
- Put 'virtual' on both the line #39 and line #46. Run it and see what will happen.
Hope this simple exercise can make you less confused.
For
dynamic, as @jamie said it is useful in the old Delphi days. It is more memory-efficient but sacrificing (a bit) performance, because the computers in the olden days have very limited memory.
Sorry, I use Lazarus. So it is easier for me to write Lazarus examples instead of FPC.
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, Forms, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;
var
Form1: TForm1;
implementation
type
{ TAnimal }
TAnimal = class
protected
function Sound: string; virtual;
public
procedure DoVocal;
end;
{ TCat }
TCat = class(TAnimal)
protected
function Sound: string; override;
end;
{ TBigCat }
TBigCat = class(TCat)
protected
function Sound: string; override;
end;
{$R *.lfm}
{ TAnimal }
function TAnimal.Sound: string;
begin
Result := '';
end;
procedure TAnimal.DoVocal;
begin
ShowMessage(Sound);
end;
{ TCat }
function TCat.Sound: string;
begin
Result := 'meow';
end;
{ TBigCat }
function TBigCat.Sound: string;
begin
Result := 'roar';
end;
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
var
aTiger: TBigCat;
begin
aTiger := TBigCat.Create;
aTiger.DoVocal;
aTiger.Free;
end;
end.
You should now know if the TAnimal.Sound is not a virtual method or the TBigCat.Sound does not override it, the result aTiger.DoVocal is always empty. You may ask why.
Because the declaration of DoVocal is in TAnimal, it is belong to TAnimal. So DoVocal will call the Sound method that belong to TAnimal (if the Sound is not virtual or it is not overridden) even you call DoVocal from TBigCat. That happens because the compiler bind the method by hardcoding it at the compile time.
The virtual-overridden tells the compiler to use VMT (virtual method table) when calling the method. Using the data, it can know which method should be called. It is called Late Binding. Read more:
https://en.wikipedia.org/wiki/Late_bindingThe generation of the VMT data happens when the constructor being called. That's why we must always call the constructor before using it.
If you follow my explanation, you may wonder why not all the methods being set as virtual-override automatically. The generation of VMT need memory and using it is slower than direct non-virtual method. So don't do it if it is not needed.