<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>VCL Developer &#187; Articles</title>
	<atom:link href="http://vcldeveloper.com/category/articles/feed/" rel="self" type="application/rss+xml" />
	<link>http://vcldeveloper.com</link>
	<description>Ali Keshavarz&#039;s Website</description>
	<lastBuildDate>Fri, 04 Nov 2011 23:40:16 +0000</lastBuildDate>
	<language>fa</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>Different function parameter modifiers in Delphi</title>
		<link>http://vcldeveloper.com/articles/different-function-parameter-modifiers-in-delphi/</link>
		<comments>http://vcldeveloper.com/articles/different-function-parameter-modifiers-in-delphi/#comments</comments>
		<pubDate>Sun, 01 Aug 2010 23:45:12 +0000</pubDate>
		<dc:creator>Ali Keshavarz</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[const]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[function]]></category>
		<category><![CDATA[parameter]]></category>
		<category><![CDATA[procedure]]></category>
		<category><![CDATA[دلفی]]></category>

		<guid isPermaLink="false">http://vcldeveloper.com/tips-tricks/different-function-parameter-modifiers-in-delphi/</guid>
		<description><![CDATA[Recently a friend asked me about constant parameters in Delphi functions, that brought the idea of writing a new post about passing parameters to functions/procedures in Delphi. Parameter modifiers When you call a function or procedure (I am going to refer to both of them as Functions here), you have to somehow pass the required [...]]]></description>
			<content:encoded><![CDATA[<p>Recently a friend asked me about constant parameters in Delphi functions, that brought the idea of writing a new post about passing parameters to functions/procedures in Delphi.</p>
<h2>Parameter modifiers</h2>
<p>When you call a function or procedure (I am going to refer to both of them as Functions here), you have to somehow pass the required input or output parameters to it. Parameters are passed to functions either by value, or by reference.</p>
<p><span style="text-decoration: underline;">Passing by value</span> means, compiler makes a new copy of the original data, and sends it to the function. This way, the function has its own copy of data, and changing value of the parameter inside the function does not affect the original data. This is the default mode when you pass a parameter to a function in Delphi:<span id="more-388"></span></p>
<pre class="brush: delphi; title: ; notranslate">
program Test02;

procedure Foo(Param1: Integer);
begin
  Inc(Param1); //=&gt; Has no effect on MyData.
end;

var
  MyData : Integer;
begin
  MyData := 1;
  Foo(MyData);
  Writeln(MyData); //=&gt; MyData is still 1.
end.
</pre>
<p><span style="text-decoration: underline;">Passing by reference</span> means, compiler only sends a pointer to the function. This pointer refers to the original data, so changing value of the parameter inside the function directly changes the original data. In Delphi such parameters are marked with <strong>var</strong> keyword:</p>
<pre class="brush: delphi; title: ; notranslate">
program Test02;

procedure Foo(Var Param1: Integer);
begin
  Inc(Param1);
end;

var
  MyData : Integer;
begin
  MyData := 1;
  Foo(MyData);
  Writeln(MyData); //=&gt; MyData is 2.
end.
</pre>
<p>These are the two basic ways parameters are passed to functions, but Delphi has still two other modifier keywords for function parameters: <strong>const</strong> and <strong>out</strong>. What are these two used for?</p>
<p>“Const” makes the parameter read-only, so that you cannot change its value inside the function. This lets compiler to generate optimized code when there is no need to alter value of that parameter inside the function.</p>
<pre class="brush: delphi; title: ; notranslate">
procedure Foo(const Param1: Integer);
begin
  Inc(Param1); // =&gt; ERROR! You cannot modify a const parameter.
end;
</pre>
<p>“Out” is similar to “var”, the difference is, when you use “Out” the initial value of the parameter is discarded inside the function, and it does not matter. What matters is the value you assign to that parameter inside your function. “Out” is basically there to support MS COM method declaration in Delphi. You can use it in any function you write, but you will see lots of COM methods having Out parameters in their declaration.</p>
<p>OK, the purpose of Const and Out modifiers are clear, it can be guessed even from their name which represent Constant and Output; but, to which category do they belong?</p>
<h2>Are “Out” and “Const” passed by value or by reference?</h2>
<p>For “out”, as I mentioned above, it acts similar to “var”, so it passes parameters by reference.</p>
<p>How about “Const’? Const acts somehow differently! It passes parameters usually by value, but it passes certain data types by reference too! Which data types are passed by value, and which ones are passed by reference? To clarify this, I wrote a simple program; it shows address of a parameter passed to a function using the default passing (by value), var modifier (by reference), and const modifier. It repeats this for various data types, to show how these modifiers pass different data types to a function. The source code is attached at the end of this post. Here is a screenshot of this sample program:</p>
<p><a href="http://vcldeveloper.com/wp-content/uploads/2010/08/function_param_modifiers.png"><img class="wlDisabledImage" style="margin: 0px auto; display: block; float: none; border-width: 0px;" title="function_param_modifiers" src="http://vcldeveloper.com/wp-content/uploads/2010/08/function_param_modifiers_thumb.png" border="0" alt="function_param_modifiers" width="424" height="407" /></a></p>
<p>For each data type, “Original:” line indicates address of the original data before being passed to the function. “Value:” line indicates address of the parameter passed to the function by value. “Const:” line indicates address of the parameter passed to the function as a constant. And finally, “var:” line indicates address of the parameter passed to the function by reference.</p>
<p>As you can see, for all data types, address of var parameter is the same as address of the original data, and address of value parameter (passed by value) differs from the original data. Therefore, we can conclude passing a parameter by value, always makes a copy of the original data; and passing a parameter with var modifier always refers to the original data, regardless of the data type which is used.</p>
<p>But for constant parameters, we can see that it always passes the parameter by value, except when the parameter is of array type (<em>static arrays and open arrays, not dynamic arrays; dynamic arrays are passed similar to objects</em>), or record type. It means, if you do not specify a modifier for a parameter of type array (<em>not dynamic arrays</em>) or records, then every time your function is called, the whole data inside that array or record will be pushed into stack, and when the execution of your function is over, it is dismissed! On the other hand, when you use Const or Var modifiers, only a pointer to your record or array is passed to the function, so there is no need to copy the whole data of the array or record.</p>
<p>Now you might ask, if the compiler is smart enough to optimize array and record parameters when Var or <strong>Const</strong> modifiers are used, then why doesn’t it use the same optimization for objects, interfaces, strings, or dynamic arrays?! The answer is: Because those are special data types!</p>
<h2>Objects, Interfaces, Strings, and Dynamic Arrays as parameters</h2>
<p>Objects, interfaces, strings, and dynamic arrays are behind the scene just pointers. They do not contain the real data. They are pointers that refer to the real data. That’s why if you call SizeOf() function on a string or object type, even if your string or object contains huge data; the result is always 4 (<em>as long as Delphi compiler is 32-bits</em>)! SizeOf() function only returns the size of that pointer, not size of the data that pointer refers to. Also that is why we have Length() function for getting size of strings and dynamic arrays, and TObject.InstanceSize class method for getting size of an object.</p>
<p>Hence, for data types as objects, interfaces, strings, or dynamic arrays; we can say practically they are always passed by reference, even if no modifier is specified for them. So the code bellow directly affects StringList variable, and there is no local copy of that object inside Foo:</p>
<pre class="brush: delphi; title: ; notranslate">
program Test03

uses Classes;

procedure Foo(Param1: TStrings);
begin
  Param1.Add(‘۱۲۳۴’); //=&gt; This will directly add a new item to StringList.
end;

var
  StringList : TStringList;
begin
  StringList : TStringList.Create;
  try
    Foo(StringList);
    WriteLn(StringList.Text); //=&gt; Writes ‘۱۲۳۴’.
  finally
    StringList.Free;
  end;
end.
</pre>
<p>Using var modifier on objects, interfaces or dynamic arrays is most of the time unnecessary, because the value itself is a reference, so using var means having a reference to another reference!</p>
<p>Also Const modifier has no particular meaning on objects, interfaces or dynamic arrays, because it only locks the pointer behind the scene, not the data structure to which the pointer is referring. So if we change declaration of Foo() in the code above to this:</p>
<pre class="brush: delphi; title: ; notranslate">
procedure Foo(const Param1: TStrings);
</pre>
<p>We will get the same result as the above code.</p>
<p>However, const and var modifiers have meaning for string types! This is because strings are a special auto-managed data types in Delphi.</p>
<h3>Strings, Dynamic Arrays, and Interfaces are referenced counted:</h3>
<p>Strings and dynamic arrays are both reference-counted. Interfaces in Delphi also provide reference-counting support). Reference-counted types are automatically handled by Delphi runtime. When you define a string variable in Delphi and assign it a value, you will have a data structure containing your text, and a reference-counter value which is set to 1:</p>
<pre class="brush: delphi; title: ; notranslate">
var
 A : string;
begin
  A := ‘Test’; // Memory is allocated for A
                  // on the heap, and reference
                  // counter is set to 1.
end;
</pre>
<p>Now if you change the above code to this:</p>
<pre class="brush: delphi; title: ; notranslate">
var
  A, B : string;
begin
  A := ‘Test’; // Memory is allocated for A
                  // on the heap, and reference
                  // counter is set to 1.
  B := A;      // Reference count for the data
                 // structure referred by A is incremented to 2.
end;
</pre>
<p>Value of A is not copied to B, instead of that, B refers to the same data structure as A, and reference counter of that data structure is set to 2. As soon as any of those variables goes out of scope, reference counter of that data structure would be decremented, and when reference counter reaches down to zero, the data structure would be automatically freed. This mechanism is the same for strings and dynamic arrays. For interfaces, the class which implements the interface should implement three methods defined inside IInterface to provide reference-counting support.</p>
<h3>Strings use Copy-On-Write technique:</h3>
<p>The biggest reason why Const and Var modifiers are meaningful to string types is their copy-on-write feature. To explain this, I had to explain reference-counting in brief. Now please take a look at this example:</p>
<pre class="brush: delphi; title: ; notranslate">
var
  A, B : string;
begin
  A := ‘Test’; // Memory is allocated for A
                  // on the heap, and reference
                  // counter is set to 1.
  B := A;      // Reference count for the data
                 // structure referred by A is incremented to 2.
  B := B + ‘er’;   // B = Tester , A = Test
end;
</pre>
<p>This is the same as the previous sample code, with one extra line. In the last line, we add ‘er’ to variable B. That will result in B referring to “Tester”, not “Test” anymore. How is it done? A and B were both referring to a data structure containing “Test”. Then we decided to modify B. Delphi runtime assigns a new data structure, and copies the string “Test” and the string “er” to it. It also decrements reference-counter of original “Test”, and changes B to refer to the new data structure. It also increments reference-counter of the new data structure. So at the end, we have A which refers to the old data structure, and B which refers to the new data structure. Reference-counters of both data structures are 1 now.</p>
<p>This is called <strong>copy-on-write</strong>; as long as there is no modification, there is no need to do the costly copy operation and waste the memory. Delphi waits until a modification is requested, at that time, it does the actual copy operation.</p>
<p>Please take note, this mechanism <span style="text-decoration: underline;">does not</span> exist for dynamic arrays, so if A and B in the code above were dynamic arrays, changing B would have affected A too.</p>
<h3>So, how does a string parameter work?</h3>
<p>When a string parameter is defined with no modifier, it is sent to the function as a reference to the actual data, but its reference-counter would be incremented when entering the function, and decremented when exiting the function. If a modification is done on the string parameter, then a new local string variable would be created inside the function, and the original value of the parameter would be copied to it (Copy-on-write operation). The change would be reflected on the local string variable. This local string variable would be released when execution of the function is over.</p>
<p>When a string parameter is defined as a constant, compiler is sure that the string cannot be modified inside the function, therefore, there is no need for it to add codes for automatic incrementing and decrementing of the reference-counter.</p>
<p>When a string parameter is defined with var modifier, then it is sent to the function as a reference to the actual data. When value of the parameter is changed, then the original data would be copied to a new memory location, and the modification would be applied to it in the new memory location:</p>
<pre class="brush: delphi; title: ; notranslate">
program Test04;

procedure Test(var Param: string);
begin
  Param := Param + Param;
end;

var
  A, B : string;
begin
  A := 'Test';
  B := A;
  Test(A);
  Writeln(A); //=&gt; A is modifed and is now “TestTest”
  Writeln(B); //=&gt; B still refers to “Test”
end.
</pre>
<p>Now back to the original question:</p>
<h2>When should we use Const modifier for parameters?</h2>
<ol>
<li>
<div>Whenever you have a parameter of type array or record, and you do not need to modify it inside your function; define it as a constant parameter to prevent expensive copy operation of array elements every time your function is called.</div>
</li>
<li>
<div>Whenever you have a parameter of type string or dynamic array, and you do not need to modify it inside your function, define it as a constant parameter to prevent compiler from generating protecting code to keep track of the reference-counter. When you do not use const modifier in such cases, compiler would add a hidden try-finally block to your function which contains code for keeping track of reference-counter for your string or dynamic array parameter. This would affect performance of your code. To read more about the impact of this, and see how much code compiler would produce in that case, you can read Eric Grange’s <a href="http://delphitools.info/2010/07/28/all-hail-the-const-parameters/" target="_blank">post on this</a>.</div>
</li>
</ol>
<p><strong><span style="text-decoration: underline;">Important Note:</span></strong> For the second recommendation above to work, you have to set “String format checking” in your project option to False. This option adds that protective try-finally block to your functions whether you define your string or dynamic array as const or not! This is for backward compatibility with some old C++ Builder codes. If you are not a C++ Builder developer, or are a C++ Builder developer, but do not have such old codes, then you MUST set this option to False in your projects. It reduces performance of strings in Delphi.</p>
<p style="text-align: center;"><a href="http://vcldeveloper.com/wp-content/uploads/2010/08/delphi_string_format_checking.png"><img class="wlDisabledImage aligncenter" style="margin: 0px 12px 0px 0px; display: inline; border-width: 0px;" title="delphi_string_format_checking" src="http://vcldeveloper.com/wp-content/uploads/2010/08/delphi_string_format_checking_thumb.png" border="0" alt="delphi_string_format_checking" width="354" height="269" /></a></p>
<p>OK, I hope this post is clarifying function parameter modifiers and their effects in Delphi programming; specially answering the question of when to use Const modifier. You can download source code and binary file of Function Parameters Type Demo<a href="/downloads/Function_Parameters_Type.zip"> from here</a>.</p>
<p>Have Fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://vcldeveloper.com/articles/different-function-parameter-modifiers-in-delphi/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>اینترفیس ها در دلفی</title>
		<link>http://vcldeveloper.com/articles/interfaces_in_delphi/</link>
		<comments>http://vcldeveloper.com/articles/interfaces_in_delphi/#comments</comments>
		<pubDate>Tue, 17 Mar 2009 22:04:45 +0000</pubDate>
		<dc:creator>Ali Keshavarz</dc:creator>
				<category><![CDATA[Articles]]></category>
		<category><![CDATA[Article]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Farsi]]></category>
		<category><![CDATA[Interfaces]]></category>
		<category><![CDATA[اینترفیس]]></category>
		<category><![CDATA[دلفی]]></category>
		<category><![CDATA[رابط]]></category>
		<category><![CDATA[فارسی]]></category>
		<category><![CDATA[مقاله]]></category>

		<guid isPermaLink="false">http://vcldeveloper.com/?p=64</guid>
		<description><![CDATA[در این مقاله تعریف مختصری از مفهوم Interface و Abstract Class در طراحی نرم افزار ارائه می کنیم، و سپس به قابلیت های نوع Interface در دلفی و برخی کاربردهای آن، با ذکر مثال، می پردازیم.]]></description>
			<content:encoded><![CDATA[<div dir="rtl">
<p>در این مقاله تعریف مختصری از مفهوم Interface و Abstract Class در طراحی نرم افزار ارائه می کنیم، و سپس به قابلیت های نوع Interface در دلفی و برخی کاربردهای آن، با ذکر مثال، می پردازیم.</p>
<h2>مقدمه</h2>
<p>نوع Interface از نسخه ۳ به دلفی اضافه شد تا پشتیبانی از تکنولوژی COM شرکت مایکروسافت در دلفی فراهم شود. Interface علاوه بر پشتیبانی از COM، قابلیت های جالبی برای برنامه نویسان دلفی به ارمغان آورد که کمتر از آن استفاده می شود. متاسفانه به دلیل آنکه چارچوب اصلی VCL و بخصوص کامپوننت های کار با بانک اطلاعاتی دلفی مدت ها قبل از آن (از نسخه اول دلفی) ایجاد شده بودند، استفاده چندانی از Interfaceها در  VCL صورت نگرفت.</p>
<p>برای درک بهتر interface ها، و قبل از آنکه به تعریف Interface و کاربردهای آن بپردازیم، ابتدا به مفهوم کلاس های Abstract و تعریف آنها اشاره ایی خواهیم داشت؛ زیرا مشابهت هایی در کاربرد این دو مفهوم وجود دارد، و شناخت مفهوم کلاس های Abstract درک مفهوم Interfaceها را ساده تر می کند.</p>
</div>
<p><span id="more-64"></span></p>
<div dir="rtl">
<h2>کلاس های Abstract</h2>
<p>در دلفی، کلاسی که حداقل یکی از متدهای آن با استفاده از رهنمود abstract تعریف شده باشد، کلاس Abstract نامیده می شود.<br />
متدهای abstract متدهایی هستند که توسط یک کلاس والد (parent) تعریف می شوند، اما پیاده سازی نمی شوند. پیاده سازی اینگونه متدها بر عهده کلاس های فرزند (child) می باشد.<br />
در صورتی که یک نمونه (instance) [ یک شی (object) ]  از یک کلاس abstract ایجاد کنید، با هشدار کامپایل مواجه خواهید شد و در صورتی که یکی از متدهای abstract آن شی را فراخوانی کنید، برنامه شما با یک استثنای EAbstractError&#8221;" متوقف خواهد شد.</p>
<p>در اینجا این سوال ممکن است مطرح شود که اصلا کلاس یا متدی که هیچ پیاده سازیی ندارد و نمی توان از آن یک نمونه شی ایجاد کرد، چه استفاده ایی ممکن است داشته باشد؟<br />
کلاس های Abstract در ساختار یک نرم افزار موجب می شوند که برنامه نویسی که پیاده سازی کلاس های فرزند را برعهده دارد، ملزم به پیاده سازی یکسری رفتارهای معین در هر یک از کلاس های خود شود؛ در غیر این صورت، با هشدارهای کامپایلر مواجه می شود. به این ترتیب احتمال اشتباه برنامه نویس (بخصوص در پروژه های بزرگ) کاهش می یابد.<br />
<span style="text-decoration: underline;">مثال :</span><br />
فرض کنید قصد داریم دو نوع پنجره طراحی کنیم (پنجره بیضوی و پنجره مستطیلی). هر دو این پنجره رفتارهای استانداردی مثل Minimize, Restore و غیره دارند. هر دو این پنجره ها باید ترسیم شوند، اما نحوه ترسیم هر یک از آنها فرق می کند. برای طراحی آنها می توانیم رفتارهای مشترک آنها را در کلاس TBaseWindow قرار دهیم و کلاس های دیگر از همین کلاس پایه، مشتق شوند. برای تعریف کلاس TBaseWindow دو روش می توانیم بکار بریم.</p>
<p>روش اول:</p>
<div dir="ltr">
<pre class="brush: delphi; title: ; notranslate">
TBaseWindow = class
private
  AField  : TSomeType;
public
  procedure Draw; virtual;
  procedure Minimize;
  procedure Maximize;
  procedure Restore;
end;
</pre>
</div>
<p>متد Draw در کلاس پایه به صورت virtual تعریف شده است، در نتیجه کلاس های TOvalWindow و TRectangularWindow (دو کلاس فرضی برای رسم پنجره بیضوی و مستطیلی، مشتق شده از کلاس پایه TBaseWindow) می توانند این متد را override کرده و پیاده سازی خود را اعمال کنند. اگر برنامه نویسان این کلاس ها فراموش کنند که متد Draw را Override کنند، تا زمان اجرای برنامه مشکلی بوجود نخواهد آمد؛ اما در زمان اجرا با فراخوانی متد Draw پنجره ایی رسم نخواهد شد!</p>
<p>روش دوم:</p>
<div dir="ltr">
<pre class="brush: delphi; title: ; notranslate">
TBaseWindow = class
private
  AField  : TSomeType;
public
  procedure Draw; virtual; abstract;
  procedure Minimize;
  procedure Maximize;
  procedure Restore;
end;
</pre>
</div>
<p>متد Draw در کلاس پایه بصورت abstract تعریف شده است. اگر برنامه نویسی که کلاس های TOvalWindow و TRectangularWindow را ایجاد می کند، فراموش کند که متد Draw را پیاده سازی کند؛ با فراخوانی متد Draw هشدار زیر را دریافت می کند:</p>
<div dir="ltr">
<p>OvalWindow.Draw;</p>
<p>Constructing instance of TOvalWindow contains abstract method TBaseWindow.Draw</p>
</div>
<h2>Interfaces</h2>
<p>اینترفیس ها نوعی قرارداد بین دو یا چند کلاس محسوب می شوند که در آن یک کلاس پیاده سازی تمامی متدهای مشخص شده در قرار داد را برای استفاده سایر کلاس ها یا کاربر تضمین می کند. پیاده سازی این متدها از دید کلاس های استفاده کننده و کاربر پنهان است. اینترفیس ها شبیه به کلاسی هستند که تمامی متد های آن abstract باشد و هیچ فیلدی برای ذخیره اطلاعات نداشته باشد.</p>
<p>اما اینترفیس ها ویژگی هایی دارند که آنها را از کلاس های Abstract جدا می کند:</p>
<p>۱-	اینترفیس ها  کلاس نیستند، بلکه یک نوع (Type) مستقل در زبان مربوطه (در اینجا Object Pascal) محسوب می شوند.<br />
۲-	اینترفیس ها از TObject مشتق نمی شوند. IUnknown در نسخه های قبلی دلفی (قبل از دلفی ۵) بعنوان والد تمام اینترفیس ها محسوب می شد، اما از نسخه ۵ به بعد، همه اینترفیس ها از IInterface مشتق می شوند.  IUnknown و IInterface یکسان هستند. از IUnknown در برنامه های مبتنی بر تکنولوژی COM مایکروسافت استفاده می شود.<br />
۳-	اگر پیدا سازی نکردن یک متد از کلاس abstract ،در کلاس های فرزند، موجب ایجاد هشدار کامپایلر می شد؛ پیاده سازی نکردن هر یک از متدهای یک اینترفیس، توسط کلاسی که آن اینترفیس را پشتیبانی می کند، موجب کامپایل نشدن برنامه می شود.<br />
۴-	یک کلاس می تواند از چندین اینترفیس بطور همزمان پشتیبانی کند.<br />
۵-	اینترفیس ها در دلفی قابلیت Reference-counting (شمارش مرجع) دارند.</p>
<p><span style="text-decoration: underline;">نکته</span>: از اینترفیس ها هم مثل کلاس های abstract نمی توان یک نمونه (شی) ایجاد کرد.</p>
<p>اینترفیس ها این امکان را به شما می دهند که خارج از ساختار سلسله مراتبی کلاس ها، قابلیت هایی را به برخی از کلاس های خود اضافه کنید. برای مثال فرض کنید شما کلاسی بنام TCar (برای تعریف یک اتومبیل) دارید که کلاس هایی مثل  TSUV, TTruck, TSedan, TVan و غیره (برای تعریف انواع اتومبیل) از آن مشتق شده اند. اگر شما قصد اضافه کردن قابلیت ۴WD (تقسیم نیروی محرکه بر روی هر چهار چرخ) به ماشین های SUV و Van داشته باشید، نمی توانید این قابلیت را در کلاس TCar پیاده سازی کنید، چون در این صورت تمامی ماشین ها از آن بهره خواهند برد. البته می توان این قابلیت را در هر یک ار این کلاس ها بصورت مستقل تعریف و پیاده سازی کرد، اما در صورت استفاده از اینترفیس (در اینجا I4wd)، هم می توانید از یک واسط مشترک استفاده کنید و هم از قابلیت های Polymorphic (چند ریختی) اینترفیس ها بهره ببرید:</p>
<div dir="ltr">
<pre class="brush: delphi; title: ; notranslate">
I4wd = interface
   ['{C2816773-A5DF-4136-AC86-27E6231DB4A9}']
   procedure Initialize4WD;
end;

TCar = class(TInterfacedObject)
public
   procedure SomeCommonBehavior;
   procedure StartEngine; virtual;
end;

TSedan = class(TCar)
public
  procedure SomeSpecificBehavior;
  procedure StartEngine; override;
end;

TSUV = class(TCar, I4wd)
public
   procedure SomeSpecificBehavior;
   procedure StartEngine; override;
   procedure Initialize4WD;
end;

TVan = class(TCar, I4wd)
public
  procedure SomeSpecificBehavior;
  procedure Initialize4WD;
end;

{نحوه استفاده}

procedure Drive4WD(A4WDCar : I4WD);
begin
  if Assigned(A4WDCar) then
  begin
     A4WDCar.Initialize4WD;
    {Add Code for driving the car here}
  end;
end;
</pre>
</div>
<p>با استفاده از رویه Drive4WD شما می توانید هر ماشینی را که از اینترفیس I4WD پشتیبانی می کند، برانید. البته هر ماشین متد Initialize4WD مربوط به خود را فراخوانی می کند. برای مثال:</p>
<div dir="ltr">Drive4WD(TVan.Create);</div>
<p>نگران آزاد کردن حافظه اشغال شده توسط TVan.Create نباشید، شی ایجاد شده بصورت خودکار آزاد خواهد شد.</p>
<div dir="rtl">
<h3>Globally Unique Identifier (GUID)</h3>
</div>
<p>عبارت  {C2816773-A5DF-4136-AC86-27E6231DB4A9}در تعریف اینترفیس بالا، یک GUID نامیده می شود. GUID عددی ۱۲۸ بیتی است (در مبنای ۱۶) که با تقریب بالایی منحصر به فرد می باشد [ تعداد کل GUID هایی که می توان ساخت ۲ به توان ۱۲۸ است و عملا احتمال اینکه دو GUID یکسان تولید شود بسیار کم است.]</p>
<p>استفاده از GUID در تعریف یک اینترفیس موجب منحصر به فرد شدن آن اینترفیس می شود، به عبارت دیگر، حتی اگر چند اینترفیس در یک سیستم با نام مشابه وجود داشته باشند، مشکلی در استفاده از آنها بوجود نمی آید. استفاده از GUID در یک اینترفیس  اجباری  نیست، اما وجود آن برای استفاده از عملگر as، متد GetInterface، تابع Supports و متد QueryInterface  (بطور کلی (Interface Querying الزامی است. اشیاء COM، اینترفیس ها و Type Library  آنها نیز باید هر کدام دارای GUID باشند.</p>
<p>برای ساخت GUID در Editor دلفی می توانید از ترکیب سه کلید Ctrl+Shift+G استفاده کنید تا دلفی برای شما یک GUID ایجاد کند.</p>
<p>نکته: هیچگاه GUID یک اینترفیس را در یک اینترفیس دیگر استفاده نکنید.</p>
<h3>استخراج یک Interface از داخل یک Class</h3>
<p>فرد متاهلی را در نظر بگرید که ریس یک شرکت می باشد. این فرد در رابطه با کارمندان خود نقش ریس، در رابطه با همسر خود نقش شوهر و در رابطه با فرزندان خود نقش پدر را ایفا می کند. در واقع این فرد در رابطه با هر گروه از افراد مذکور طبق یک رسم یا توافق مشترک، عمل می کند. هر یک از این گروه ها نیز بر اساس همان توافق یا رسم با این فرد ارتباط برقرار می کند و فقط به نقش مربوط به خود نیاز دارد (مثلا یک کارمند نیازی به دانستن رابطه ریس خود با همسر و فرزندانش ندارد). در دنیای نرم افزار هم یک کلاس می تواند با پیاده سازی اینترفیس های مختلف، نقش های مختلفی را در ارتباط با دنیای خارج بر عهده بگیرد.</p>
<p>حال، فرد فوق را بعنوان یک کلاس و توافق او با هر یک از گروه های فوق را به عنوان یک اینترفیس در نظر می گیریم:<br />
هر گروه (درخواست کننده؛ هر شی در دنیای خارج از آن کلاس) باید ابتدا بررسی کند که آیا فرد  (کلاس پیاده سازی کننده )  مذکور به رسومات و توافق مشخص شده (اینترفیس)  پایبند هست یا نه، اگر آن کلاس از اینترفیس مشخص شده پشتیبانی کند، درخواست کننده می تواند، بر اساس همان اینترفیس، درخواست خود را به آن کلاس ارائه دهد و جواب دریافت کند (استخراج یک اینترفیس از کلاسی که آن را پیاده سازی می کند).</p>
<p>در دلفی برای بررسی پشتیبانی کردن یک کلاس از یک اینترفیس خاص و استخراج آن اینترفیس می توان از تابع Supports در یونیت SysUtils، متد QueryInterface از هر کلاسی که IInterface را پشتیبانی می کند (مثل TInterfaceObject)  ، عملگر as، یا متد GetInterface در کلاس TObject استفاده کرد.[۱]</p>
<p>به روش های مختلف استخراج اینترفیس I4WD از کلاس TSUV در مثال زیر توجه کنید:</p>
<div dir="ltr">
<pre class="brush: delphi; title: ; notranslate">
var
SUV : TSUV;
A4wdInterface : I4WD;
begin
  {If TSuv implements I4WD (supports it), extract the interface.}
  if Supports(TSUV.Create,I4WD,A4wdInterface) then
  {Invoke Initialize4WD from returned interface.}
  A4wdInterface.Initialize4WD;

  //----------------------------------
  {Just check if TSuv supports I4WD, no interface is returned.}
  if Supports(TSuv,I4WD) then
  ShowMessage('TSuv supports I4WD interface');

  //----------------------------------
  SUV := TSUV.Create;
  {If you are sure than SUV supports I4WD, use as operator to extract
  the interface and invoke Initialize4WD.
  If SUV does not support I4WD, an exception will be thrown.}
  (SUV as I4wd).Initialize4WD;

  //----------------------------------
  SUV := TSUV.Create;
  {If Suv implements I4WD (supports it), extract the interface.}
  if SUV.GetInterface(I4WD,A4wdInterface) then
  A4wdInterface.Initialize4WD;

  //----------------------------------
  {TSUV supports I4WD, so you can assign an instance of it to a variable of type I4WD.}
  A4wdInterface := TSuv.Create;
  A4wdInterface.Initialize4WD;
end;
</pre>
</div>
<p>* تمامی توابع و عملگرهای فوق در راهنمای دلفی توضیح داده شده اند.</p>
<h3>Multiple Inheritance (وراثت چندگانه)</h3>
<p>در زبانهایی مثل دلفی، C#، و جاوا وراثت چندگانه امکان پذیر نیست &#8211; یعنی یک کلاس نمی تواند مثل C++ از چند کلاس والد مشتق شود. اما در این زبان ها امکان پیاده سازی چند اینترفیس توسط یک کلاس وجود دارد و می تواند به نوعی این خلاء را پر کند. مثلا کلاس TMyMobile (یک کلاس فرضی مربوط به گوشی موبایل) می تواند بطور همزمان اینترفیس های IInfraRed و IBlueTooth را پیاده سازی کند:</p>
<div dir="ltr">
<pre class="brush: delphi; title: ; notranslate">
TMyMobile = class(TInterfaceObject, IInfraRed, IBlueTooth)
  {TMobile's fields and methods + IInfraRed's methods + IBlueThoot's methods}
end;
</pre>
</div>
<h3>Reference counting (شمارش مرجع)</h3>
<p>یکی از ویژگی های مهم اینترفیس ها در دلفی (همچنین در COM) خصوصیت Reference Counting آنها ست. با استفاده از این قابلیت اشیاء ایجاد شده بصورت خودکار مدیریت می شوند و در صورتی که نیازی به آنها نباشد، بطور خودکار آزاد می شوند. متدهای مربوط به این قابلیت در اینترفیس IInterface تعریف شده اند.<br />
هر بار که اینترفیسی از یک کلاس استخراج می شود یا نمونه ایی از یک کلاس به متغیری از یک اینترفیس اختصاص داده می شود، دلفی متد _AddRef از اینترفیس IInterface را فراخوانی می کند. هر زمان که آن متغیر نا معتبر شود (با اختصاص مقدار nil به آن یا خارج شدن از محدوده تعریف آن متغیر)، دلفی متد _Release را فراخوانی می کند. شما به عنوان برنامه نویس وظیفه دارید که متغیری در کلاس خود تعریف کرده (برای ذخیره شماره مرجع) و این متد ها را پیاده سازی کنید. با اجرای _AddRef باید یک واحد به شماره مرجع اضافه شود. با اجرای _Release باید یک واحد از شماره مرجع کم شود، اگر شماره مرجع به صفر رسید، _Release وظیفه آزاد کردن شی ایجاد شده را بر عهده دارد.</p>
<p>در صورتی که تمایلی به پیاده سازی متدهای فوق ندارید، می توانید کلاس خود را از کلاس TInterfacedObject مشتق بگیرید. در این صورت کلاس TInterfacedObject قابلیت شمارش مرجع را برای کلاس شما پیاده سازی خواهد کرد. TInterfacedObject در یونیت System تعریف شده است. بهتر است کد آن را مطالعه نمایید.</p>
<p>به مثال های زیر در رابطه با کاربرد Reference Counting توجه کنید:</p>
<div dir="ltr">
<pre class="brush: delphi; title: ; notranslate">
procedure TForm1.Button3Click(Sender: TObject);
var
  SUV : TSUV;
  Van : TVan;
  AnInterface,
  AnotherInterface : I4WD;
begin
  Memo1.Clear;
  SUV := TSuv.Create;
  //SUV.RefCount = 0
  AnInterface := SUV;
  //SUV.RefCount = 1
  AnotherInterface := SUV;
  //SUV.RefCount = 2

  Van := TVan.Create;
  //Van.RefCount = 0;
  AnInterface := Van;
  //SUV.RefCount = 1
  //Van.RefCount = 1
end;
//&quot; AnInterface&quot; is out of scope: SUV.RefCount = 0
//SUV is destroyed
//AnotherInterface is out of scope: Van.RefCount = 0
//Van is destroyed
</pre>
</div>
<p>در مثال بالا به تغییرات RefCount توجه کنید:<br />
زمانی که SUV به یک اینترفیس اختصاص داده می شود، یک واحد به شمارشگر مرجع آن افزوده می شود.<br />
با اختصاص SUV به اینترفیس بعدی (AnotherInterface)، شمارشگر مرجع آن به ۲ می رسد.<br />
با اختصاص  Vanبه اینترفیس AnInterface ، شمارشگر مرجع این شی یک واحد افزایش پیدا می کند، ولی شمارشگر مرجع شی SUV که قبلا به AnInterface اختصاص داده شده بود، یک واحد کاهش پیدا می کند.<br />
در پایان این متد، هیچ کدی برای آزاد سازی متغیرهای SUV و Van وجود ندارد؛ اما با پایان یافتن کد Form1.Button3Click، متغیرهای AnInterface و AnotherInterface که بصورت محلی تعریف شده اند، نامعتبر می شوند و با نامعتبر شدن هر یک از آنها، یک واحد از شمارشگر مرجع هر یک از اشیاء اختصاص یافته به آنها کاهش میابد. با صفر شدن شمارشگر مرجع هر شی، آن شی آزاد می شود.</p>
<p>Malcome Groves در مقاله Interfaces: Off the Beaten Track مثالی از پیاده سازی قابلیت Garbage Collection با استفاده از اینترفیس ارائه کرده است[۲] :</p>
<div dir="ltr">
<pre class="brush: delphi; title: ; notranslate">
unit mtReaper;

interface

type
ImtReaper = interface
  ['{1B321324-975F-4026-B742-E7B3AD486BB5}']
end;

TmtReaper = class(TInterfacedObject, ImtReaper)
private
  FObject : TObject;
public
  constructor Create(AObject : TObject);
  destructor Destroy; override;
end;

implementation

uses SysUtils;

constructor TmtReaper.Create(AObject: TObject);
begin
  FObject := AObject;
end;

destructor TmtReaper.Destroy;
begin
  FreeAndNil(FObject);
  inherited;
end;

end.
</pre>
</div>
<p>در این کد کلاس ساده ایی ((TmtReaper تعریف شده که Garbage Collection را برای شما انجام می دهد. با ارسال یک شی به متد Create این کلاس، شی مورد نظر در زمان مقتضی آزاد خواهد شد و نیازی نیست که شما شخصا آن شی را آزاد کنید:</p>
<div dir="ltr">
<pre class="brush: delphi; title: ; notranslate">
var
  List : TStringList;
  mtReaper : ImtReaper;
begin
  List := TStringList.Create;
  mtReaper := TmtReaper.Create(List);

  //Use List in your code
  List.LoadFromFile('A File Name');
  List.Sort;
end;
//List will be destroyed automatically by mtReaper
</pre>
</div>
<p>در دلفی ۲۰۰۹ می توان این قابلیت را با استفاده از مفهوم Smart Pointers به شکل مناسب تری پیاده سازی کرد.</p>
<p>۲۷ مهر ۱۳۸۴  (بازنگری: ۱۳ اسفند ۱۳۸۷)</p>
<hr />
<h2>پاورقی</h2>
<p>[۱] &#8211; در واقع تمامی روش های ذکر شده در داخل خود به نوعی از متد GetInterface استفاده می کنند.</p>
<p>[۲] &#8211; Delphi Magazine شماره ۸۰٫</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://vcldeveloper.com/articles/interfaces_in_delphi/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: enhanced
Database Caching 1/14 queries in 0.052 seconds using disk: basic
Object Caching 1239/1269 objects using disk: basic

Served from: vcldeveloper.com @ 2012-02-04 21:48:31 -->
