Bizim inceleyeceğimiz türü ise Subtyping Polymorphism.
Subtyping Polymorphism'in implementasyonundaki ilüzyon ise şu şekilde açıklanabilir; Derleyici virtual method (yada diğer adıyla function) tanımlı bir sınıf tespit ettiğinde, sınıfın içerisine fonksiyonların pointer(adres) bilgilerini tutacağı gizli bir array, diğer adıyla virtual method table(VMT) yerleştirmekte ve daha sonra bu array içerisindeki pointerlara (adreslere), alt sınıfta ki fonksiyonların pointer bilgisini set etmektedir.
Fonksiyon pointer'larının çalışma zamanında set edilmesi veya değiştirilmesinin diğer adı "run time method binding" yada late binding olarak ifade edilmektedir.
Kod üzerinden mekanizmanın nasıl çalıştığını anlamaya çalışalım.
C++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stdafx.h" | |
class Calculation | |
{ | |
public: | |
virtual int Calc(int x, int y) = 0; | |
}; | |
class CalculationSum :public Calculation | |
{ | |
public: | |
int Calc(int x, int y); | |
}; | |
class CalculationDiv :public Calculation | |
{ | |
public: | |
int Calc(int x, int y); | |
}; | |
int CalculationSum::Calc(int x, int y) | |
{ | |
return x + y; | |
} | |
int CalculationDiv::Calc(int x, int y) | |
{ | |
return x / y; | |
} | |
int _tmain(int argc, _TCHAR* argv[]) | |
{ | |
int result = 0; | |
Calculation *calculation; | |
calculation = new CalculationSum(); | |
result = calculation->Calc(5, 5); | |
calculation = new CalculationDiv(); | |
result = calculation->Calc(10, 2); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
program Project2; | |
{$APPTYPE CONSOLE} | |
{$R *.res} | |
uses | |
System.SysUtils; | |
type | |
TCalculation = class | |
public | |
function Calc(X: Integer; Y: Integer): Integer; virtual; abstract; | |
end; | |
TCalculationSum = class(TCalculation) | |
public | |
function Calc(X: Integer; Y: Integer): Integer; override; | |
end; | |
TCalculationDiv = class(TCalculation) | |
public | |
function Calc(X: Integer; Y: Integer): Integer; override; | |
end; | |
var | |
calculation: TCalculation; | |
iResult: Integer; | |
{ TCalculationSum } | |
function TCalculationSum.Calc(X, Y: Integer): Integer; | |
begin | |
Result := X + Y; | |
end; | |
{ TCalculationDiv } | |
function TCalculationDiv.Calc(X, Y: Integer): Integer; | |
begin | |
Result := X div Y; | |
end; | |
begin | |
try | |
calculation := TCalculationSum.Create; | |
iResult := calculation.Calc(5, 5); | |
calculation := TCalculationDiv.Create; | |
iResult := calculation.Calc(10, 2); | |
except on E: Exception do | |
Writeln(E.ClassName, ': ', E.Message); | |
end; | |
end. |
Yukarıda ki C++ kod bloğunda Calculation sınıfında Calc ismine sahip bir pure virtual function ve yine Calculation sınıfından miras alan CalculationSum ve CalculationDiv sınıflarını görmekteyiz.
Kodu çalıştırıp, inceleyecek olursak; Calculation sınıfı içersinde ki Calc fonksiyonunun,CalculationSum(Sub Class) içinde ki Calc fonksiyonuna yönlendirildiği,diğer adıyla method binding işleminin gerçekleştiğini görebiliriz.
calculation ve CalculationSum içersinde vftable array'lerin, ilk elemanlarında ki Calc fonksiyonlarına ait adreslerin(Sarı ile çizili) aynı olduğu görebiliriz.
Class,virtual function olmasaydı,yada method binding işlemini biz yapmak isteseydik basit olarak nasıl yapabilirdik ?
C++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "stdafx.h" | |
int (*Calc)(int x, int y); | |
int CalculateSum(int x, int y) | |
{ | |
return x + y; | |
} | |
int CalculateDiv(int x, int y) | |
{ | |
return x / y; | |
} | |
int _tmain(int argc, _TCHAR* argv[]) | |
{ | |
int result = 0; | |
Calc = CalculateSum; | |
result = Calc(5, 5); | |
Calc = CalculateDiv; | |
result = Calc(10, 2); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
program Project1; | |
{$APPTYPE CONSOLE} | |
{$R *.res} | |
uses | |
System.SysUtils; | |
type | |
PCalc = ^TCalc; | |
TCalc = function(X: Integer; Y: Integer): Integer; | |
function CalculateSum(X: Integer; Y: Integer): Integer; | |
begin | |
Result := X + Y; | |
end; | |
function CalculateDiv(X: Integer; Y: Integer): Integer; | |
begin | |
Result := X div Y; | |
end; | |
var | |
Calc: PCalc; | |
iResult: Integer; | |
begin | |
try | |
Calc := @CalculateSum; | |
iResult := TCalc(Calc)(5, 5); | |
Calc := @CalculateDiv; | |
iResult := TCalc(Calc)(10, 2); | |
except | |
on E: Exception do | |
Writeln(E.ClassName, ': ', E.Message); | |
end; | |
end. |
Son olarak bu konuyu araştırmamı salık veren Tuğrul Beye teşekkür etmeden geçmek olmaz. :)