Original in Russian: http://programmingmindstream.blogspot.ru/2014/04/supports_4.html
The previous series was here – Briefly. Peculiarities of Supports (in Russian)
I was asked here:
http://programmingmindstream.blogspot.ru/2014/04/supports.html?showComment=1396620657041#c4522417805967527391 (in Russian)
Quote of the question: "Excuse me, but I do not understand why we expect С if it is a method of the TC class. We do not create an object, right?"
I’ll develop the theme.
So, we had an example:
Let us write in THIS way:
Do you understand me?
I have change only ONE line and how GREAT IS THE DIFFERENCE!
Let’s move on.
Now we write in this way:
AMAZING!
Isn’t it?
UNSYMMETRY of the Supports method is OBVIOUS.
In my opinion...
"A takeaway":
overload is "harmful", “in general” and, in THIS CASE, “in particular”.
overload with “covariant” types is very harmful.
Generally speaking, we could handle with the Supports(IUnknown) method ONLY (if Borland's stead) instead of creating another VERY UNOBVIOUS method Supports(TObject).
Is the idea clear?
Let me note, it is not “for everybody”.
That is why, do not rush to comment before you “grokk” the problem.
I hope I helped.
P.S. If such “exercises” of objects vs. interfaces are INTERESTING, let me know. I have some thoughts in store.
P.P.S. I also hope you understand that GUID in description to interfaces are OMITTED. They can be added at Crtl-Shift-G.
P.P.P.S. On the topic:
More about QueryInterface (in Russian)
Again about Supports
Oh yeah! Supports (in Russian)
P.P.P.P.S. One of my readers kindly provided me with a compilable example - https://bitbucket.org/ingword/temp/src
The previous series was here – Briefly. Peculiarities of Supports (in Russian)
I was asked here:
http://programmingmindstream.blogspot.ru/2014/04/supports.html?showComment=1396620657041#c4522417805967527391 (in Russian)
Quote of the question: "Excuse me, but I do not understand why we expect С if it is a method of the TC class. We do not create an object, right?"
I’ll develop the theme.
So, we had an example:
type
ISomeInterface = interface
procedure SomeMethod;
end;//ISomeInterface
TA = class(TObject, ISomeInterface {IUnknown is omitted FOR PURPOSE here})
function _AddRef: Integer;
function _Release: Integer;
function QueryInterface(const anID: TGUID; out anObj): hResult; virtual;
procedure SomeMethod;
end;//TA
TB = class(TA)
function QueryInterface(const anID: TGUID; out anObj): hResult; override;
end;//TB
TC = class(TIntefacedObject, ISomeInterface)
procedure SomeMethod;
end;//TC
...
function TA._AddRef: Integer;
begin
Result := -1;
end;
function TA._Release: Integer;
begin
Result := -1;
end;
function TA.QueryInterface(const anID: TGUID; out anObj): hResult;
begin
if Self.GetInterface(anID, anObj) then
Result := S_Ok
else
Result := E_NoInterface;
end;
procedure TA.SomeMethod;
begin
Write('A');
end;
function TB.QueryInterface(const anID: TGUID; out anObj): hResult;
begin
if IsEqualGUID(anID, ISomeInterface) then
begin
Result := S_Ok;
ISomeInterface(Obj) := TC.Create;
end//IsEqualGUID(anID, ISomeInterface)
else
Result := inherited QueryInterface(anID, Obj);
end;
procedure TC.SomeMethod;
begin
Write('C');
end;
...
var
l_A : ISomeInterface;
l_B : ISomeInterface;
A : TA;
B : TB;
begin
A := TA.Create;
B := TB.Create;
if not Supports(A, ISomeInterface, l_A) then
Assert(false);
l_A.SomeMethod; // - A is seen in console
if not Supports(B, ISomeInterface, l_B) then
Assert(false);
l_B.SomeMethod; // - A is seen in console, and we need C
end;
Let us write in THIS way:
type
ISomeInterface = interface
procedure SomeMethod;
end;//ISomeInterface
TA = class(TObject, IUnknown {IUnknown APPEARS here}, ISomeInterface)
function _AddRef: Integer;
function _Release: Integer;
function QueryInterface(const anID: TGUID; out anObj): hResult; virtual;
procedure SomeMethod;
end;//TA
TB = class(TA)
function QueryInterface(const anID: TGUID; out anObj): hResult; override;
end;//TB
TC = class(TIntefacedObject, ISomeInterface)
procedure SomeMethod;
end;//TC
...
function TA._AddRef: Integer;
begin
Result := -1;
end;
function TA._Release: Integer;
begin
Result := -1;
end;
function TA.QueryInterface(const anID: TGUID; out anObj): hResult;
begin
if Self.GetInterface(anID, anObj) then
Result := S_Ok
else
Result := E_NoInterface;
end;
procedure TA.SomeMethod;
begin
Write('A');
end;
function TB.QueryInterface(const anID: TGUID; out anObj): hResult;
begin
if IsEqualGUID(anID, ISomeInterface) then
begin
Result := S_Ok;
ISomeInterface(Obj) := TC.Create;
end//IsEqualGUID(anID, ISomeInterface)
else
Result := inherited QueryInterface(anID, Obj);
end;
procedure TC.SomeMethod;
begin
Write('C');
end;
...
var
l_A : ISomeInterface;
l_B : ISomeInterface;
A : TA;
B : TB;
begin
A := TA.Create;
B := TB.Create;
if not Supports(A, ISomeInterface, l_A) then
Assert(false);
l_A.SomeMethod; // - A is seen in console
if not Supports(B, ISomeInterface, l_B) then
Assert(false);
l_B.SomeMethod; // - NOW C is seen in the console
end;
Do you understand me?
I have change only ONE line and how GREAT IS THE DIFFERENCE!
Let’s move on.
Now we write in this way:
type
ISomeFakeInterface = interface
end;//ISomeFakeInterface
ISomeInterface = interface
procedure SomeMethod;
end;//ISomeInterface
TA = class(TObject, ISomeInterface {IUnknown is omitted FOR PURPOSE here}, ISomeFakeInterface)
function _AddRef: Integer;
function _Release: Integer;
function QueryInterface(const anID: TGUID; out anObj): hResult; virtual;
procedure SomeMethod;
end;//TA
TB = class(TA)
function QueryInterface(const anID: TGUID; out anObj): hResult; override;
end;//TB
TC = class(TIntefacedObject, ISomeInterface)
procedure SomeMethod;
end;//TC
...
function TA._AddRef: Integer;
begin
Result := -1;
end;
function TA._Release: Integer;
begin
Result := -1;
end;
function TA.QueryInterface(const anID: TGUID; out anObj): hResult;
begin
if Self.GetInterface(anID, anObj) then
Result := S_Ok
else
Result := E_NoInterface;
end;
procedure TA.SomeMethod;
begin
Write('A');
end;
function TB.QueryInterface(const anID: TGUID; out anObj): hResult;
begin
if IsEqualGUID(anID, ISomeInterface) then
begin
Result := S_Ok;
ISomeInterface(Obj) := TC.Create;
end//IsEqualGUID(anID, ISomeInterface)
else
Result := inherited QueryInterface(anID, Obj);
end;
procedure TC.SomeMethod;
begin
Write('C');
end;
...
var
l_A : ISomeInterface;
l_B : ISomeInterface;
A : TA;
B : TB;
begin
A := TA.Create;
B := TB.Create;
if not Supports(A, ISomeInterface, l_A) then
Assert(false);
l_A.SomeMethod; // - A is seen in console
if not Supports(B, ISomeInterface, l_B) then
Assert(false);
l_B.SomeMethod; // - A is seen in console, and we need C
if not Supports(ISomeFakeInterface(B), ISomeInterface, l_B) then
Assert(false);
l_B.SomeMethod; // - C is seen in console, TA DA!!!
end;
AMAZING!
Isn’t it?
UNSYMMETRY of the Supports method is OBVIOUS.
In my opinion...
"A takeaway":
overload is "harmful", “in general” and, in THIS CASE, “in particular”.
overload with “covariant” types is very harmful.
Generally speaking, we could handle with the Supports(IUnknown) method ONLY (if Borland's stead) instead of creating another VERY UNOBVIOUS method Supports(TObject).
Is the idea clear?
Let me note, it is not “for everybody”.
That is why, do not rush to comment before you “grokk” the problem.
I hope I helped.
P.S. If such “exercises” of objects vs. interfaces are INTERESTING, let me know. I have some thoughts in store.
P.P.S. I also hope you understand that GUID in description to interfaces are OMITTED. They can be added at Crtl-Shift-G.
P.P.P.S. On the topic:
More about QueryInterface (in Russian)
Again about Supports
Oh yeah! Supports (in Russian)
P.P.P.P.S. One of my readers kindly provided me with a compilable example - https://bitbucket.org/ingword/temp/src
Комментариев нет:
Отправить комментарий