3. کلاسها، ساختارها، رابطها
3.1. ابجهها به عنوان مثال
3.1.1. عمومی
اکنون برنامهنویسی شیءگرا را از طریق مثالها بررسی خواهیم کرد. یک شیء یک موجودیت است که شامل دادههایی است که وضعیت آن را تعریف میکنند (که به آنها ویژگیها گفته میشود) و توابع (که به آنها متدها گفته میشود). یک شیء بر اساس قالبی به نام کلاس ایجاد میشود:
Public Class c1
' ویژگیها
Private p1 As type1
Private p2 As type2
....
' روش
Public Sub m1(....)
...
End Sub
' روش
Public Function m2(...)
....
End Function
End Class
از کلاس قبلی C1، میتوان اشیاء متعددی مانند O1، O2، … ایجاد کرد. همهٔ اینها دارای خواص p1، p2 و ... و متدهای m3، m4 و ... خواهند بود. با این حال، مقادیر خواص آنها متفاوت است، به این معنی که هر pi وضعیت متمایز خود را دارد. به طور مشابه، اعلان
دو شیء (این اصطلاح در اینجا نادرست است) از نوع (کلاس) Integer ایجاد میکند. تنها ویژگی آنها مقدارشان است. اگر O1 یک شیء از نوع C1 باشد، O1.p1 به خصوصیت p1 از O1 اشاره میکند، و O1.m1 به متد m1 از QZXW2HTMLP0003 اشاره میکند.06ZQX. بیایید یک مدل شیء اولیه را در نظر بگیریم: کلاس personne.
3.1.2. تعریف کلاس Person
تعریف کلاس personne به شرح زیر خواهد بود:
Public Class personne
' ویژگیها
Private prenom As String
Private nom As String
Private age As Integer
' روش
Public Sub initialise(ByVal P As String, ByVal N As String, ByVal age As Integer)
Me.prenom = P
Me.nom = N
Me.age = age
End Sub
' روش
Public Sub identifie()
Console.Out.WriteLine((prenom & "," & nom & "," & age))
End Sub
End Class
در اینجا ما تعریف یک کلاس و در نتیجه یک نوع داده را داریم. هنگامی که متغیرهایی از این نوع ایجاد میکنیم، به آنها اشیاء یا نمونههای کلاس میگوییم. بنابراین یک کلاس یک قالب است که اشیاء از روی آن ساخته میشوند. اعضای یا فیلدهای یک کلاس میتوانند داده (ویژگیها)، متدها (تابعها) یا خواص باشند. خواص، متدهای خاصی هستند که برای بازیابی یا تنظیم مقدار ویژگیهای یک شیء استفاده میشوند. این فیلدها ممکن است با یکی از سه کلمه کلیدی زیر همراه باشند:
یک فیلد خصوصی تنها توسط متدهای داخلی کلاس قابل دسترسی است | |
یک فیلد عمومی برای هر تابع قابل دسترسی است، چه در داخل کلاس تعریف شده باشد چه نباشد | |
یک فیلد محافظتشده تنها از طریق متدهای داخلی کلاس یا توسط یک شیء مشتقشده قابل دسترسی است (مفهوم ارثبری را بعداً ببینید). |
بهطور کلی، دادههای یک کلاس بهصورت خصوصی اعلام میشوند، در حالی که متدها و ویژگیهای آن بهصورت عمومی اعلام میشوند. این بدان معناست که کاربر یک شیء (برنامهنویس):
- دسترسی مستقیم به دادههای خصوصی شیء نخواهد داشت
- میتواند متدهای عمومی شیء را فراخوانی کند، بهویژه آنهایی که دسترسی به دادههای خصوصی آن را فراهم میکنند.
سینتکس تعریف یک کلاس به شرح زیر است:
public class classe
private donnée ou méthode ou propriété privée
public donnée ou méthode ou propriété publique
protected donnée ou méthode ou propriété protégée
end class
ترتیب اعلام خصوصیات private، protected و public دلخواه است.
3.1.3. متد مقداردهی اولیه میکند
بیایید به کلاس [personne] خود بازگردیم که به صورت زیر تعریف شده است:
Public Class personne
' ویژگیها
Private prenom As String
Private nom As String
Private age As Integer
' روش
Public Sub initialise(ByVal P As String, ByVal N As String, ByVal age As Integer)
Me.prenom = P
Me.nom = N
Me.age = age
End Sub
' روش
Public Sub identifie()
Console.Out.WriteLine((prenom & "," & nom & "," & age))
End Sub
End Class
نقش متد initialise چیست؟ از آنجا که nom، prenom و age اعضای خصوصی کلاس personne هستند، دستورات:
نامعتبر هستند. ما باید یک شیء از نوع personne را از طریق یک متد عمومی مقداردهی اولیه کنیم. این وظیفه متد initialise است. خواهیم نوشت:
نوتاسیون p1.initialise معتبر است زیرا initialise بهصورت عمومی قابل دسترسی است.
3.1.4. اپراتور جدید
ترتیب دستورالعملها
نادرست است. دستور
p1 را بهعنوان مرجعی به یک شیء از نوع personne اعلام میکند. این شیء هنوز وجود ندارد و بنابراین p1 مقداردهی اولیه نمیشود. گویی که کسی بنویسد:
که در آن کلمه کلیدی nothing صراحتاً نشان میدهد که متغیر p1 هنوز به هیچ شیئی ارجاع نمیدهد. وقتی سپس مینویسیم
ما در حال فراخوانی متد initialise از شیای هستیم که توسط p1 ارجاع شده است. با این حال، این شی هنوز وجود ندارد و کامپایلر خطا گزارش خواهد کرد. برای اینکه p1 به یک شی ارجاع دهد، باید بنویسیم:
این کار یک شیء از نوع personne ایجاد میکند که هنوز مقداردهی اولیه نشده است: ویژگیهای nom و prenom، که ارجاع به اشیایی از نوع String هستند، مقدار nothing را خواهند داشت، و age مقدار 0 را خواهد داشت. بنابراین یک مقداردهی پیشفرض وجود دارد. اکنون که p1 به یک شیء ارجاع میدهد، عبارت مقداردهی اولیه برای آن شیء
صحیح است.
3.1.5. کلمه کلیدی Me
بیایید کد متد initialise را بررسی کنیم:
Public Sub initialise(ByVal P As String, ByVal N As String, ByVal age As Integer)
Me.prenom = P
Me.nom = N
Me.age = age
End Sub
دستور Me.prenom=P به این معناست که ویژگی prenom از شیء فعلی (Me) مقدار P را دریافت میکند. کلمه کلیدی Me به شیء فعلی اشاره دارد: شیئی که متدی که در حال اجراست در آن قرار دارد. چگونه این را میدانیم؟ بیایید ببینیم که شیء مرجع p1 در برنامه فراخوانیکننده چگونه مقداردهی اولیه میشود:
این متد initialise از شیء p1 است که فراخوانی میشود. وقتی در این متد به شیء Me ارجاع داده میشود، در واقع به شیء p1 ارجاع داده میشود. روش initialise میتوانست به صورت زیر نیز نوشته شود:
Public Sub initialise(ByVal P As String, ByVal N As String, ByVal age As Integer)
prenom = P
nom = N
Me.age = age
End Sub
وقتی یک متد یک شی به یک ویژگی A از آن شی ارجاع میدهد، نشانه Me.A بهطور ضمنی در نظر گرفته میشود. در مواردی که بین شناسهها تداخل وجود دارد، باید بهطور صریح از آن استفاده شود. این مورد در عبارت زیر صادق است:
Me.age=age;
که در آن age به یک ویژگی از شیء جاری و همچنین پارامتر age دریافتی توسط متد اشاره میکند. آنگاه باید این ابهام با ارجاع به صفت age بهعنوان Me.age برطرف شود.
3.1.6. یک برنامهٔ آزمایشی
در اینجا یک برنامه آزمایشی کوتاه آمده است:
Public Class personne
' ویژگیها
Private prenom As String
Private nom As String
Private age As Integer
' روش
Public Sub initialise(ByVal P As String, ByVal N As String, ByVal age As Integer)
Me.prenom = P
Me.nom = N
Me.age = age
End Sub
' روش
Public Sub identifie()
Console.Out.WriteLine((prenom & "," & nom & "," & age))
End Sub
End Class
و نتایج بهدستآمده:
dos>vbc personne1.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
3.1.7. استفاده از یک فایل کلاس کامپایلشده (اسمبلی)
توجه کنید که در مثال قبلی، دو کلاس در برنامه آزمایشی ما وجود دارد: کلاسهای personne و test1. راه دیگری برای انجام این کار وجود دارد:
-
کلاس «person» را در یک فایل جداگانه به نام assembly کامپایل میکنیم. این فایل دارای پسوند .dll است.
-
ما کلاس **
test1**را با ارجاع به اسمبلی حاوی کلاسpersonکامپایل میکنیم.
دو فایل منبع به شکل زیر درمیآیند:
test.vb | |
personne2.vb | |
کلاس personne توسط عبارت زیر کامپایل میشود:
dos>vbc /t:library personne2.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
dos>dir
24/02/2004 16:50 509 personne2.vb
24/02/2004 16:49 143 test.vb
24/02/2004 16:50 3 584 personne2.dll
مجموعهسازی فایلی به نام personne2.dll تولید کرد. این گزینهٔ مجموعهسازی /t:library است که تولید یک فایل «اسمبلی» را مشخص میکند. اکنون بیایید فایل test.vb را مجموعهسازی کنیم:
dos>vbc /r:personne2.dll test.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
dos>dir
24/02/2004 16:50 509 personne2.vb
24/02/2004 16:49 143 test.vb
24/02/2004 16:50 3 584 personne2.dll
24/02/2004 16:51 3 072 test.exe
گزینهٔ کامپایل /r:personne2.dll به کامپایلر میگوید که کلاسهای خاصی را در فایل personne2.dll پیدا خواهد کرد. وقتی در فایل منبع test.vb، ارجاعی به کلاس personne – کلاسی که در فایل منبع test.vb تعریف نشده است – پیدا میکند، این کلاس را در فایلهای .dll که توسط گزینه /r ارجاع شدهاند، جستجو خواهد کرد. در اینجا، کلاس personne را در اسمبلی personne2.dll پیدا خواهد کرد. میتوانست کلاسهای دیگری نیز در این اسمبلی گنجانده شوند. برای استفاده از چندین فایل کلاس کامپایلشده در طول کامپایل، باید مینوشت:
اجرای برنامه test1.exe نتایج زیر را تولید میکند:
3.1.8. یک متد دیگر مقداردهی اولیه شده است
بیایید دوباره کلاس personne را در نظر بگیریم و متد زیر را به آن اضافه کنیم:
' روش
Public Sub initialise(ByVal P As personne)
prenom = P.prenom
nom = P.nom
Me.age = P.age
End Sub
اکنون ما دو متد با نام initialise داریم: این امر تا زمانی که پارامترهای متفاوتی را بپذیرند مجاز است. در اینجا نیز همینطور است. پارامتر اکنون یک مرجع (P) به یک شخص است. ویژگیهای شخص P سپس به شیء فعلی (Me) تخصیص داده میشوند. توجه داشته باشید که متد initialise دسترسی مستقیم به ویژگیهای شیء P دارد، هرچند این ویژگیها از نوع private هستند. این امر همیشه صادق است: یک شیء O1 از کلاس C همیشه به ویژگیهای اشیاء از همان کلاس، C، دسترسی دارد. در اینجا آزمایش کلاس جدید personne ارائه شده است که همانطور که قبلاً توضیح داده شد، به personne.dll کامپایل شده است:
' گزینهها
Option Explicit On
Option Strict On
' فضاهای نام
Imports System
Module test1
Sub Main()
Dim p1 As New personne
p1.initialise("Jean", "Dupont", 30)
Console.Out.Write("p1=")
p1.identifie()
Dim p2 As New personne
p2.initialise(p1)
Console.Out.Write("p2=")
p2.identifie()
End Sub
End Module
و نتایج آن:
3.1.9. سازندههای کلاس Person
یک سازنده، روندی به نام New است که هنگام ایجاد شی فراخوانی میشود. این معمولاً برای مقداردهی اولیه شی استفاده میشود. اگر یک کلاس دارای سازندهای باشد که n آرگومان را میپذیرد argi، میتوان یک شی از آن کلاس را به صورت زیر اعلام و مقداردهی اولیه کرد:
dim objet as classe =new classe(arg1,arg2, ... argn)
یا
dim objet as classe
…
objet=new classe(arg1,arg2, ... argn)
وقتی یک کلاس یک یا چند سازنده دارد، باید از یکی از این سازندهها برای ایجاد یک شیء از آن کلاس استفاده شود. اگر یک کلاس C هیچ سازندهای نداشته باشد، یک سازندهٔ پیشفرض دارد که همان سازندهٔ بدونپارامتر است: public New(). سپس ویژگیهای شیء با مقادیر پیشفرض مقداردهی میشوند. این همان چیزی است که در برنامههای قبلی رخ داد، جایی که ما نوشته بودیم:
بیایید دو سازنده برای کلاس personne خود ایجاد کنیم:
' گزینهها
Option Explicit On
Option Strict On
' فضاهای نام
Imports System
' کلاس Person
Public Class personne
' ویژگیها
Private prenom As String
Private nom As String
Private age As Integer
' سازندهها
Public Sub New(ByVal P As [String], ByVal N As [String], ByVal age As Integer)
initialise(P, N, age)
End Sub
Public Sub New(ByVal P As personne)
initialise(P)
End Sub
' روشهای инициализация شیء
Public Sub initialise(ByVal P As String, ByVal N As String, ByVal age As Integer)
Me.prenom = P
Me.nom = N
Me.age = age
End Sub
Public Sub initialise(ByVal P As personne)
prenom = P.prenom
nom = P.nom
Me.age = P.age
End Sub
' متد
Public Sub identifie()
Console.Out.WriteLine((prenom & "," & nom & "," & age))
End Sub
End Class
هر دو کانستراکتور ما به سادگی متدهای متناظر initialise را فراخوانی میکنند. به یاد داشته باشید که وقتی در داخل یک کانستراکتور، به عنوان مثال، با notation initialise(P) مواجه میشویم، کامپایلر این را به Me.initialise(P) تبدیل میکند. بنابراین در داخل سازنده، متد initialise برای عمل بر روی ابجکتی که توسط Me ارجاع شده است، یعنی همان ابجکت فعلی که در حال ساخت است، فراخوانی میشود. در اینجا یک برنامه آزمایشی کوتاه آورده شده است:
' گزینهها
Option Explicit On
Option Strict On
' فضاهای نام
Imports System
' صفحه آزمایشی
Module test
Sub Main()
Dim p1 As New personne("Jean", "Dupont", 30)
Console.Out.Write("p1=")
p1.identifie()
Dim p2 As New personne(p1)
Console.Out.Write("p2=")
p2.identifie()
End Sub
End Module
و نتایج بهدستآمده:
3.1.10. اشارههای شیء
ما همیشه از همان کلاس personne استفاده میکنیم. برنامهٔ آزمایشی به شرح زیر است:
' گزینهها
Option Explicit On
Option Strict On
' فضاهای نام
Imports System
' صفحه آزمایشی
Module test
Sub Main()
' p1
Dim p1 As New personne("Jean", "Dupont", 30)
Console.Out.Write("p1=")
p1.identifie()
' p2 به همان شیء p1 اشاره میکند
Dim p2 As personne = p1
Console.Out.Write("p2=")
p2.identifie()
' p3 به شیای اشاره میکند که کپیای از شی مورد اشارهٔ p1 خواهد بود
Dim p3 As New personne(p1)
Console.Out.Write("p3=")
p3.identifie()
' وضعیت شیء مرجع p1 تغییر میکند
p1.initialise("Micheline", "Benoît", 67)
Console.Out.Write("p1=")
p1.identifie()
' از آنجا که p2 = p1، حالت شی ارجاعشده توسط p2 باید تغییر کرده باشد
Console.Out.Write("p2=")
p2.identifie()
' از آنجا که p3 به همان شیء p1 اشاره نمیکند، شیء مورد اشاره p3 نباید تغییر کرده باشد
Console.Out.Write("p3=")
p3.identifie()
End Sub
End Module
نتایج بهدستآمده به شرح زیر است:
p1=Jean,Dupont,30
p2=Jean,Dupont,30
p3=Jean,Dupont,30
p1=Micheline,Benoît,67
p2=Micheline,Benoît,67
p3=Jean,Dupont,30
وقتی متغیر p1 با استفاده از
p1 به شیء personne("Jean","Dupont",30) اشاره میکند اما خود شیء نیست. در C میگوییم که این یک اشارهگر (pointer) به نشانی شیء ایجادشده است. اگر سپس بنویسیم:
این شیء personne("Jean","Dupont",30) نیست که تغییر میکند؛ بلکه مرجع p1 است که مقدار آن تغییر میکند. شیء personne("Jean","Dupont",30) «گم» خواهد شد اگر توسط هیچ متغیر دیگری ارجاع داده نشود.
وقتی مینویسید:
اشارهگر p2 مقداردهی اولیه میشود: این اشارهگر به همان شیئی اشاره میکند (یا به همان شیئی ارجاع میدهد) که اشارهگر p1 به آن اشاره میکند. بنابراین، اگر ما شیء «اشارهشده» (یا مرجع) توسط p1 را تغییر دهیم، در واقع همان شیء مرجع توسط p2 را تغییر میدهیم.
وقتی مینویسیم:
یک شیء جدید ایجاد میشود که کپیای از شیء مرجع p1 است. این شیء جدید توسط p3 مرجعدهی خواهد شد. اگر شیء «اشارهشده» (یا مرجع) توسط p1 تغییر یابد، شیء مرجع p3 کاملاً بدون تغییر باقی میماند. این موضوع با نتایج بهدستآمده نشان داده شده است.
3.1.11. ابجکتهای موقت
در یک عبارت، میتوان بهطور صریح سازنده (constructor) یک شیء را فراخوانی کرد: شیء ایجاد میشود، اما ما به آن دسترسی نداریم (برای مثال برای تغییر آن). این شیء موقت برای هدف ارزیابی عبارت ایجاد میشود و سپس دور ریخته میشود. فضای حافظهای که اشغال کرده بود، بعداً بهطور خودکار توسط برنامهای به نام «جمعکننده زباله» (garbage collector) بازیابی میشود که وظیفهاش بازیابی فضای حافظهای است که توسط اشیایی که دیگر توسط دادههای برنامه ارجاع داده نمیشوند، اشغال شده است. بیایید برنامه آزمایشی جدید زیر را در نظر بگیریم:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
' صفحهٔ آزمایشی
Module test
Sub Main()
Dim p As New personne(New personne("Jean", "Dupont", 30))
p.identifie()
End Sub
End Module
و بیایید سازندههای کلاس personne را طوری تغییر دهیم که پیامی را نمایش دهند:
' سازندهها
Public Sub New(ByVal P As [String], ByVal N As [String], ByVal age As Integer)
Console.Out.WriteLine("Constructeur personne(String, String, integer)")
initialise(P, N, age)
End Sub
Public Sub New(ByVal P As personne)
Console.Out.WriteLine("Constructeur personne(personne)")
initialise(P)
End Sub
نتایج زیر را به دست میآوریم:
dos>test
Constructeur personne(String, String, integer)
Constructeur personne(personne)
Jean,Dupont,30
نشاندهنده ساخت متوالی دو شیء موقت.
3.1.12. متدهای خواندن و نوشتن ویژگیهای خصوصی
ما متدهای لازم را به کلاس personne برای خواندن یا تغییر وضعیت ویژگیهای اشیاء اضافه میکنیم:
Imports System
Public Class personne
' ویژگیها
Private prenom As [String]
Private nom As [String]
Private age As Integer
' سازندهها
Public Sub New(ByVal P As [String], ByVal N As [String], ByVal age As Integer)
Me.prenom = P
Me.nom = N
Me.age = age
End Sub
Public Sub New(ByVal P As personne)
Me.prenom = P.prenom
Me.nom = P.nom
Me.age = P.age
End Sub
' شناسهها
Public Sub identifie()
Console.Out.WriteLine((prenom + "," + nom + "," + age))
End Sub
' دسترسکنندهها
Public Function getPrenom() As [String]
Return prenom
End Function
Public Function getNom() As [String]
Return nom
End Function
Public Function getAge() As Integer
Return age
End Function
'تعدیلکنندهها
Public Sub setPrenom(ByVal P As [String])
Me.prenom = P
End Sub
Public Sub setNom(ByVal N As [String])
Me.nom = N
End Sub
Public Sub setAge(ByVal age As Integer)
Me.age = age
End Sub
End Class
ما کلاس جدید را با برنامه زیر آزمایش میکنیم:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
' صفحه آزمایشی
Public Module test
Sub Main()
Dim P As New personne("Jean", "Michelin", 34)
Console.Out.WriteLine(("P=(" & P.getPrenom() & "," & P.getNom() & "," & P.getAge() & ")"))
P.setAge(56)
Console.Out.WriteLine(("P=(" & P.getPrenom() & "," & P.getNom() & "," & P.getAge() & ")"))
End Sub
End Module
و نتایج زیر را به دست میآوریم:
3.1.13. ویژگیها
راه دیگری برای دسترسی به ویژگیهای یک کلاس وجود دارد: با ایجاد پراپرتیها. این پراپرتیها به ما امکان میدهند ویژگیهای خصوصی را طوری دستکاری کنیم که گویی عمومی هستند. کلاس زیر personne را در نظر بگیرید که در آن گترها و سترهای قبلی با پراپرتیهای قابلخواندن و نوشتن جایگزین شدهاند:
' گزینهها
Option Explicit On
Option Strict On
' فضاهای نام
Imports System
' کلاس شخص
Public Class personne
' ویژگیها
Private _prenom As [String]
Private _nom As [String]
Private _age As Integer
'
Public Sub New(ByVal P As [String], ByVal N As [String], ByVal age As Integer)
Me._prenom = P
Me._nom = N
Me._age = age
End Sub
Public Sub New(ByVal P As personne)
Me._prenom = P._prenom
Me._nom = P._nom
Me._age = P._age
End Sub
' شناسایی میکند
Public Sub identifie()
Console.Out.WriteLine((_prenom & "," & _nom & "," & _age))
End Sub
' ویژگیها
Public Property prenom() As String
Get
Return _prenom
End Get
Set(ByVal Value As String)
_prenom = Value
End Set
End Property
Public Property nom() As String
Get
Return _nom
End Get
Set(ByVal Value As String)
_nom = Value
End Set
End Property
Public Property age() As Integer
Get
Return _age
End Get
Set(ByVal Value As Integer)
' آیا سن معتبر است؟
If Value >= 0 Then
_age = Value
Else
Throw New Exception("âge (" & Value & ") invalide")
End If
End Set
End Property
End Class
یک ویژگی به شما امکان میدهد مقدار یک صفت را بخوانید (دریافت کنید) یا آن را تنظیم کنید. در مثال ما، نامهای صفات را با یک زیرخط (_) شروع کردهایم تا ویژگیها نامهای یکسانی با صفات اولیه داشته باشند. این به این دلیل است که یک ویژگی نمیتواند نام یکسانی با صفتی که مدیریت میکند داشته باشد؛ در غیر این صورت، در داخل کلاس یک تداخل نامی رخ خواهد داد. بنابراین، ما ویژگیهای خود را _prenom، _nom و _age نامگذاری کرده و سازندهها و متدها را متناسب با آن تغییر دادیم. سپس سه ویژگی ایجاد کردیم: nom، prenom و age. یک ویژگی به صورت زیر تعریف میشود:
Public Property nom() As Type
Get
...
End Get
Set(ByVal Value As Type)
...
End Set
End Property
که در آن Type باید نوع صفتی باشد که توسط خاصیت مدیریت میشود. این ممکن است دو متد به نامهای get و set داشته باشد. متد get معمولاً مسئول بازگرداندن مقدار صفتی است که مدیریت میکند (میتواند چیز دیگری را بازگرداند؛ چیزی مانع این کار نیست). روش set پارامتری به نام value میگیرد که معمولاً آن را به ویژگیای که مدیریت میکند اختصاص میدهد. این روش میتواند از این فرصت استفاده کند تا اعتبار مقدار دریافتی را بررسی کند و در صورت لزوم، اگر مقدار نامعتبر باشد، یک استثنا (exception) پرتاب (throw) کند. این کاری است که در اینجا برای سن انجام شده است.
این متدهای get و set چگونه فراخوانی میشوند؟ بیایید برنامه آزمایشی زیر را در نظر بگیریم:
' گزینهها
Option Explicit On
Option Strict On
' فضاهای نام
Imports System
' صفحهٔ آزمایشی
Module test
Sub Main()
Dim P As New personne("Jean", "Michelin", 34)
Console.Out.WriteLine(("P=(" & P.prenom & "," & P.nom & "," & P.age & ")"))
P.age = 56
Console.Out.WriteLine(("P=(" & P.prenom & "," & P.nom & "," & P.age & ")"))
Try
P.age = -4
Catch ex As Exception
Console.Error.WriteLine(ex.Message)
End Try
End Sub
End Module
در عبارت
ما در پی به دست آوردن مقادیر ویژگیهای prenom، nom و age برای شخص P هستیم. این متد get این ویژگیها است که فراخوانی میشود و مقدار ویژگیای را که مدیریت میکند، برمیگرداند.
در عبارت
ما میخواهیم مقدار ویژگی age را تنظیم کنیم. سپس متد set این ویژگی فراخوانی میشود. این متد مقدار 56 را به عنوان پارامتر value خود دریافت خواهد کرد.
یک ویژگی P از کلاس C که فقط متد get را تعریف میکند، ویژگی فقط-خواندنی (read-only) نامیده میشود. اگر c یک شیء از کلاس C باشد، عملیات c.P=value توسط کامپایلر رد خواهد شد.
اجرای برنامه آزمایشی قبلی نتایج زیر را تولید میکند:
بنابراین، ویژگیها به ما امکان میدهند تا ویژگیهای خصوصی را طوری دستکاری کنیم که گویی عمومی هستند.
3.1.14. متدها و ویژگیهای کلاس
فرض کنید بخواهیم تعداد اشیاء [personne] ایجادشده در یک برنامه را بشماریم. میتوانیم خودمان یک شمارنده را مدیریت کنیم، اما در معرض این خطر هستیم که اشیاء موقتی را که اینجا و آنجا ایجاد میشوند نادیده بگیریم. به نظر میرسد امنتر باشد که در سازندههای کلاس [personne] یک عبارت را قرار دهیم که شمارنده را افزایش میدهد. مشکل، ارسال یک مرجع به این شمارنده است تا سازنده بتواند آن را افزایش دهد: باید یک پارامتر جدید به آن ارسال شود. همچنین میتوان شمارنده را در تعریف کلاس گنجاند. از آنجا که این یک ویژگی (attribute) خود کلاس است و نه ویژگی یک شیء خاص از آن کلاس، به شیوهای متفاوت با استفاده از کلمه کلیدی Shared اعلام میشود:
برای ارجاع به آن، personne._nbPersonnes را مینویسیم تا نشان دهیم که این یک ویژگی از خود کلاس personne است. در اینجا، ما یک ویژگی خصوصی ایجاد کردهایم که از خارج کلاس به آن دسترسی مستقیم وجود ندارد. بنابراین یک ویژگی عمومی ایجاد میکنیم تا دسترسی به ویژگی کلاس nbPersonnes را فراهم کنیم. برای تعیین مقدار nbPersonnes، متد get این خاصیت به یک شیء personne خاص نیاز ندارد: در واقع، _nbPersonnes ویژگی یک شیء خاص نیست؛ بلکه ویژگی یک کلاس کامل است. بنابراین، ما همچنین به یک ویژگی با اعلامیهای مشابه Shared نیاز داریم:
که از خارج با استفاده از نحو personne.nbPersonnes فراخوانی خواهد شد. این ویژگی بهصورت فقطخواندنی (ReadOnly) اعلام شده است زیرا متد تعیین مقدار ندارد. در اینجا یک مثال آمده است. کلاس personne به شکل زیر درمیآید:
Option Explicit On
Option Strict On
' فضاهای نام
Imports System
'کلاس
Public Class personne
' ویژگیهای کلاس
Private Shared _nbPersonnes As Long = 0
' ویژگیهای نمونه
Private _prenom As [String]
Private _nom As [String]
Private _age As Integer
' سازندهها
Public Sub New(ByVal P As [String], ByVal N As [String], ByVal age As Integer)
' یک شخص دیگر
_nbPersonnes += 1
Me._prenom = P
Me._nom = N
Me._age = age
End Sub
Public Sub New(ByVal P As personne)
' یک شخص دیگر
_nbPersonnes += 1
Me._prenom = P._prenom
Me._nom = P._nom
Me._age = P._age
End Sub
' شناسایی میکند
Public Sub identifie()
Console.Out.WriteLine((_prenom & "," & _nom & "," & _age))
End Sub
' ویژگی کلاس
Public Shared ReadOnly Property nbPersonnes() As Long
Get
Return _nbPersonnes
End Get
End Property
' ویژگیهای نمونه
Public Property prenom() As String
Get
Return _prenom
End Get
Set(ByVal Value As String)
_prenom = Value
End Set
End Property
Public Property nom() As String
Get
Return _nom
End Get
Set(ByVal Value As String)
_nom = Value
End Set
End Property
Public Property age() As Integer
Get
Return _age
End Get
Set(ByVal Value As Integer)
' سن معتبر؟
If Value >= 0 Then
_age = Value
Else
Throw New Exception("âge (" & Value & ") invalide")
End If
End Set
End Property
End Class
با برنامه زیر:
' گزینهها
Option Explicit On
Option Strict On
' فضاهای نام
Imports System
' پایگاه داده آزمایشی
Module test
Sub Main()
Dim p1 As New personne("Jean", "Dupont", 30)
Dim p2 As New personne(p1)
Console.Out.WriteLine(("Nombre de personnes créées : " & personne.nbPersonnes))
End Sub
End Module
نتایج زیر به دست میآیند:
3.1.15. ارسال یک شیء به یک تابع
ما قبلاً اشاره کردهایم که، به طور پیشفرض، VB.NET پارامترهای واقعی یک تابع را به صورت ارزشی منتقل میکند: مقادیر پارامترهای واقعی در پارامترهای اسمی کپی میشوند. در مورد یک شیء، نباید از سوءاستفاده سیستماتیک از اصطلاحات گمراه شد، جایی که از اصطلاح «شیء» به جای «اشارهگر شیء» استفاده میشود. یک شیء تنها از طریق یک مرجع (اشارهگر) به آن قابل دستکاری است. بنابراین آنچه به یک تابع ارسال میشود خودِ شیء نیست، بلکه مرجعی به آن شیء است. در نتیجه، این مقدار مرجع است که به پارامتر شکلی کپی میشود، نه مقدار خودِ شیء: هیچ شیء جدیدی ایجاد نمیشود. اگر یک مرجع شیء R1 به یک تابع ارسال شود، آن در پارامتر شکلی متناظر R2 کپی خواهد شد. در نتیجه، ارجاعات R2 و R1 به یک شیء واحد اشاره میکنند. اگر تابع شیء اشاره شده توسط R2 را تغییر دهد، واضح است که همان شیء اشاره شده توسط R1 را نیز تغییر میدهد، زیرا این دو یکی هستند.
![]() |
این موضوع با مثال زیر نشان داده میشود:
' گزینهها
Option Explicit On
Option Strict On
' فضاهای نام
Imports System
' صفحه آزمایشی
Module test
Sub Main()
' یک شخص p1
Dim p1 As New personne("Jean", "Dupont", 30)
' نمایش p1
Console.Out.Write("Paramètre effectif avant modification : ")
p1.identifie()
' ویرایش p1
modifie(p1)
' نمایش p1
Console.Out.Write("Paramètre effectif après modification : ")
p1.identifie()
End Sub
Sub modifie(ByVal P As personne)
' نمایش شخص P
Console.Out.Write("Paramètre formel avant modification : ")
P.identifie()
'ویرایش P
P.prenom = "Sylvie"
P.nom = "Vartan"
P.age = 52
'نمایش P
Console.Out.Write("Paramètre formel après modification : ")
P.identifie()
End Sub
End Module
نتایج بهدستآمده به شرح زیر است:
Paramètre effectif avant modification : Jean,Dupont,30
Paramètre formel avant modification : Jean,Dupont,30
Paramètre formel après modification : Sylvie,Vartan,52
Paramètre effectif après modification : Sylvie,Vartan,52
میتوان دید که تنها یک شیء ایجاد شده است: شیء مربوط به شخص p1 از رویه Main، و این که شیء واقعاً توسط تابع modifie تغییر داده شده است.
3.1.16. یک آرایه از افراد
یک شیء مانند هر دادهٔ دیگری است و به همین دلیل، میتوان چندین شیء را در یک آرایه گروهبندی کرد:
' گزینهها
Option Explicit On
Option Strict On
' فضاهای نام
Imports System
' صفحهٔ آزمایشی
Module test
Sub Main()
' جدولی از افراد
Dim amis(2) As personne
amis(0) = New personne("Jean", "Dupont", 30)
amis(1) = New personne("Sylvie", "Vartan", 52)
amis(2) = New personne("Neil", "Armstrong", 66)
' نمایش
Console.Out.WriteLine("----------------")
Dim i As Integer
For i = 0 To amis.Length - 1
amis(i).identifie()
Next i
End Sub
End Module
دستور Dim friends(2) As person یک آرایه با ۳ عنصر از نوع personne ایجاد میکند. این ۳ عنصر در اینجا با مقادیر nothing و c.a.d مقداردهی اولیه شدهاند، به این معنی که به هیچ شیئی ارجاع نمیدهند. بار دیگر، در معنایی کلی، وقتی به یک «آرایه از اشیاء» اشاره میکنیم، در واقع صرفاً با یک آرایه از ارجاعات به اشیاء سروکار داریم. ایجاد آرایهٔ اشیاء — که خود یک شیء است — هیچ شیء جدیدی از نوع عناصر خود ایجاد نمیکند: این کار باید به صورت جداگانه انجام شود. نتایج زیر به دست میآیند:
3.2. ارثبری به مثاله
3.2.1. عمومی
در اینجا مفهوم ارثبری را بررسی میکنیم. هدف از ارثبری، «سفارشیسازی» یک کلاس موجود است تا نیازهای ما را برآورده کند. فرض کنید میخواهیم کلاسی به نام enseignant ایجاد کنیم: معلم یک نوع خاص از شخص است. آنها ویژگیهایی دارند که دیگران ندارند: برای مثال، موضوعی که تدریس میکنند. اما آنها همچنین ویژگیهای مشترک همه افراد را دارند: نام، نام خانوادگی و سن. بنابراین، یک معلم عضو کامل کلاس personne است اما ویژگیهای اضافی نیز دارد. به جای ایجاد یک کلاس enseignant از صفر، ترجیح میدهیم بر روی ساختار موجود کلاس personne بنا کنیم و آن را با ویژگیهای خاص معلمان تطبیق دهیم. این مفهوم ارثبری است که به ما این امکان را میدهد. برای بیان اینکه کلاس enseignant از ویژگیهای کلاس personne ارث میبرد، مینویسیم:
Public Class enseignant
Inherits personne
به سینتکس خاص دو خطی توجه کنید. کلاس personne کلاس والد (یا مادر) و کلاس enseignant کلاس مشتق (یا دختر) نامیده میشود. یک شیء از نوع enseignant تمام ویژگیهای یک شیء از نوع personne را داراست: این شیء دارای همان ویژگیها و متدها است. این ویژگیها و متدهای کلاس والد در تعریف کلاس فرزند تکرار نمیشوند؛ در عوض، تنها ویژگیها و متدهایی که توسط کلاس فرزند اضافه شدهاند، مشخص میشوند. ما فرض میکنیم که کلاس personne به صورت زیر تعریف شده است:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
' کلاس شخص
Public Class personne
' ویژگیهای کلاس
Private Shared _nbPersonnes As Long = 0
' ویژگیهای نمونه
Private _prenom As [String]
Private _nom As [String]
Private _age As Integer
' سازندهها
Public Sub New(ByVal P As [String], ByVal N As [String], ByVal age As Integer)
' یک شخص دیگر
_nbPersonnes += 1
' ساختمان
Me._prenom = P
Me._nom = N
Me._age = age
' ردیابی
Console.Out.WriteLine("Construction personne(string, string, int)")
End Sub
Public Sub New(ByVal P As personne)
' یک شخص دیگر
_nbPersonnes += 1
'ساخت
Me._prenom = P._prenom
Me._nom = P._nom
Me._age = P._age
' نظارت
Console.Out.WriteLine("Construction personne(string, string, int)")
End Sub
' ویژگی کلاس
Public Shared ReadOnly Property nbPersonnes() As Long
Get
Return _nbPersonnes
End Get
End Property
' ویژگیهای نمونه
Public Property prenom() As String
Get
Return _prenom
End Get
Set(ByVal Value As String)
_prenom = Value
End Set
End Property
Public Property nom() As String
Get
Return _nom
End Get
Set(ByVal Value As String)
_nom = Value
End Set
End Property
Public Property age() As Integer
Get
Return _age
End Get
Set(ByVal Value As Integer)
' سن معتبر؟
If Value >= 0 Then
_age = Value
Else
Throw New Exception("âge (" & Value & ") invalide")
End If
End Set
End Property
Public ReadOnly Property identite() As String
Get
Return "personne(" & _prenom & "," & _nom & "," & age & ")"
End Get
End Property
End Class
متد identifie با خاصیت فقط-خواندنی identité که شخص را شناسایی میکند، جایگزین شده است. ما یک کلاس enseignant را از کلاس personne ارث میبریم:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Public Class enseignant
Inherits personne
' ویژگیها
Private _section As Integer
' سازنده
Public Sub New(ByVal P As String, ByVal N As String, ByVal age As Integer, ByVal section As Integer)
MyBase.New(P, N, age)
Me._section = section
' ردیابی
Console.Out.WriteLine("Construction enseignant(string,string,int,int)")
End Sub
' ویژگی بخش
Public Property section() As Integer
Get
Return _section
End Get
Set(ByVal Value As Integer)
_section = Value
End Set
End Property
End Class
کلاس enseignant به متدها و ویژگیهای کلاس personne اضافه میکند:
- یک ویژگی section، که شماره بخشی است که معلم در میان کادر تدریس به آن تعلق دارد (تقریباً هر درس یک بخش)
- یک سازندهٔ جدید برای مقداردهی اولیهٔ تمام ویژگیهای یک معلم
اعلام
Public Class enseignant
Inherits personne
نشان میدهد که کلاس enseignant از کلاس personne مشتق شده است.
3.2.2. ایجاد یک شیء معلم
سازنده کلاس enseignant به شرح زیر است:
' سازنده
Public Sub New(ByVal P As String, ByVal N As String, ByVal age As Integer, ByVal section As Integer)
MyBase.New(P, N, age)
Me._section = section
' ردیابی
Console.Out.WriteLine("Construction enseignant(string,string,int,int)")
End Sub
اعلامیه
Public Sub New(ByVal P As String, ByVal N As String, ByVal age As Integer, ByVal section As Integer)
مشخص میکند که سازنده چهار پارامتر میگیرد: P، N، age و section. باید سه مورد از آنها، (P,N,age)، را به کلاس پایه خود، در این مورد کلاس personne، ارسال کند. میدانیم که این کلاس دارای یک سازنده person(string, string, int) است که امکان ایجاد یک شخص را با استفاده از پارامترهای ارسالشده، (P,N,age)، فراهم میکند. کلاس [enseignant] پارامترهای (P, N, age) را به کلاس پایه خود به صورت زیر ارسال میکند:
MyBase.New(P, N, age)
پس از نمونهسازی کلاس پایه، نمونهسازی شی enseignant با اجرای بدنهٔ سازنده ادامه مییابد:
Me._section = section
خلاصه اینکه، سازنده یک کلاس مشتق:
- پارامترهایی را که برای ساخت خود نیاز دارد به کلاس پایه خود ارسال میکند
- از سایر پارامترها برای مقداردهی اولیه ویژگیهای خود استفاده میکند
ممکن بود ترجیح داده شود که به این صورت نوشته شود:
Public Sub New(ByVal P As String, ByVal N As String, ByVal age As Integer, ByVal section As Integer)
Me._prenom = P
Me._nom = N
Me._age = age
Me._section = section
' ردیابی
Console.Out.WriteLine("Construction enseignant(string,string,int,int)")
End Sub
این امکانپذیر نیست. کلاس personne سه فیلد خود _prenom، _nom و _age را به صورت خصوصی (private) اعلام کرده است. فقط اشیاء همان کلاس به این فیلدها دسترسی مستقیم دارند. تمام اشیاء دیگر، از جمله اشیاء فرزند در این مورد، باید برای دسترسی به آنها از متدهای عمومی استفاده کنند. این وضعیت متفاوت میشد اگر کلاس personne سه فیلد را به صورت محافظتشده (protected) اعلام میکرد (protected): در این صورت به کلاسهای مشتق اجازه دسترسی مستقیم به این سه فیلد داده میشد. بنابراین در مثال ما، استفاده از سازنده کلاس والد، راهحل صحیح و رویکرد استاندارد بود: هنگام ساخت یک شیء فرزند، ابتدا سازنده شیء والد فراخوانی میشود و سپس مراحل اولیه خاص شیء فرزند (section در مثال ما) تکمیل میگردد.
بیایید کلاسهای personne و enseignant را به اسمبلیها کامپایل کنیم:
dos>vbc /t:library personne.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
dos>vbc /r:personne.dll /t:library enseignant.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
dos>dir
25/02/2004 10:08 1 828 personne.vb
25/02/2004 10:11 675 enseignant.vb
25/02/2004 10:12 223 test.vb
25/02/2004 10:16 4 096 personne.dll
25/02/2004 10:16 3 584 enseignant.dll
توجه داشته باشید که برای کامپایل کلاس فرزند enseignant، لازم بود به فایل personne.dll که حاوی کلاس personne است، ارجاع داده شود. بیایید یک برنامه آزمایشی اول را امتحان کنیم:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Module test
Sub Main()
Console.Out.WriteLine(New enseignant("Jean", "Dupont", 30, 27).identite)
End Sub
End Module
این برنامه به سادگی یک شیء enseignant جدید ایجاد میکند و آن را شناسایی میکند. کلاس enseignant متدی به نام identité ندارد، اما کلاس والد آن چنین متدی دارد که آن نیز عمومی است: از طریق ارثبری، این متد به یک متد عمومی در کلاس enseignant تبدیل میشود. نتایج بهدستآمده به شرح زیر است:
dos>vbc /r:personne.dll /r:enseignant.dll test.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
dos>test
Construction personne(string, string, int)
Construction enseignant(string,string,int,int)
personne(Jean,Dupont,30)
میتوانیم ببینیم که:
- یک شیء personne قبل از شیء enseignant ایجاد شده است
- هویت بهدستآمده، هویت شیء personne است
3.2.3. سرشارژ کردن یک متد یا خاصیت
در مثال قبلی، ما شناسه بخش personne از معلم را داشتیم، اما جزئیات خاصی که مختص کلاس enseignant (بخش) بود، وجود نداشت. بنابراین ما باید یک ویژگی برای شناسایی معلم تعریف کنیم:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Public Class enseignant
Inherits personne
' ویژگیها
Private _section As Integer
' سازنده
Public Sub New(ByVal P As String, ByVal N As String, ByVal age As Integer, ByVal section As Integer)
MyBase.New(P, N, age)
Me._section = section
' ردیابی
Console.Out.WriteLine("Construction enseignant(string,string,int,int)")
End Sub
' ویژگی بخش
Public Property section() As Integer
Get
Return _section
End Get
Set(ByVal Value As Integer)
_section = Value
End Set
End Property
' خاصیت بازنویسی هویت
Public Shadows ReadOnly Property identite() As String
Get
Return "enseignant(" & MyBase.identite & "," & _section & ")"
End Get
End Property
End Class
متد identite از کلاس enseignant به متد identite از کلاس والد خود (MyBase.identite) متکی است. برای نمایش بخش «personne» خود، سپس این را با فیلد _section که مختص کلاس enseignant است، تکمیل میکند. توجه داشته باشید که اعلان خاصیت identite:
Public Shadows ReadOnly Property identite() As String
که نشان میدهد ویژگی «identite» متد همنام را که ممکن است در کلاس والد وجود داشته باشد، «پنهان» میکند. یک شیء E از نوع enseignant را در نظر بگیرید. این شیء درون خود یک شیء personne را در بر دارد:
![]() |
ویژگی identity هم در کلاس enseignant و هم در کلاس والد آن، personne، تعریف شده است. در کلاس فرزند enseignant، ویژگی identite باید با کلمه کلیدی «shadows» پیشفرض قرار گیرد تا نشان دهد که یک ویژگی جدید، identite، برای کلاس enseignant. مجدداً تعریف میشود.
Public Shadows ReadOnly Property identite() As String
کلاس enseignant اکنون دارای دو ویژگی identite است:
- یکی ارثبرده از کلاس والد personne
- خودش
اگر E یک شیء از نوع enseignant باشد، E.identite به متد identite از کلاس enseignant اشاره میکند. گفته میشود که ویژگی identite از کلاس والد توسط ویژگی identite از کلاس فرزند «پوشانده شده» است. بهطور کلی، اگر O یک شیء و M یک متد باشد، برای اجرای متد O.M، سیستم به دنبال متدی با نام M به ترتیب زیر میگردد:
- در کلاس شیء O
- در کلاس والد آن، اگر وجود داشته باشد
- در کلاس والد کلاس والد آن، اگر وجود داشته باشد
- و غیره…
وراثت بنابراین اجازه میدهد که متدها و ویژگیهایی با همان نامِ متدها و ویژگیهای کلاس والد، در کلاس فرزند دوباره تعریف شوند. این همان چیزی است که کلاس فرزند را قادر میسازد تا با نیازهای خود تطبیق یابد. ترکیبِ بارگذاری مجددِ متدها و ویژگیها با چندریختی (polymorphism) که کمی بعد به آن خواهیم پرداخت، اصلیترین مزیتِ وراثت است. بیایید همان مثالِ قبل را در نظر بگیریم:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Module test
Sub Main()
Console.Out.WriteLine(New enseignant("Jean", "Dupont", 30, 27).identite)
End Sub
End Module
این بار، نتایج به شرح زیر است:
Construction personne(string, string, int)
Construction enseignant(string,string,int,int)
enseignant(personne(Jean,Dupont,30),27)
3.2.4. پلیمورفیسم
یک تبار از کلاسها را در نظر بگیرید: C0 C1 C2 … جایی که Ci Cj نشان میدهد کلاس Cj از کلاس Ci مشتق شده است. این بدان معناست که کلاس Cj دارای تمام ویژگیهای کلاس Ci بهعلاوه ویژگیهای دیگر است. فرض کنید Oi اشیایی از نوع Ci باشند. نوشتن زیر مجاز است:
در واقع، با ارثبری، کلاس Cj تمام ویژگیهای کلاس Ci به علاوه ویژگیهای دیگر را دارد. بنابراین، یک شیء Oj از نوع Cj در درون خود یک شیء از نوع Ci را در بر دارد. عمل
به این معنی است که Oi یک مرجع به شی از نوع Ci است که در شی Oj جای گرفته است.
این واقعیت که یک متغیر Oi از کلاس Ci در واقع میتواند نه تنها به یک شیء از کلاس Ci بلکه به هر شیئی که از کلاس Ci مشتق شده است، اشاره کند، به عنوان چندریختی (polymorphism) شناخته میشود: توانایی یک متغیر برای اشاره به انواع مختلف اشیاء. بیایید یک مثال بزنیم و تابع زیر را در نظر بگیریم که به هیچ کلاسی وابسته نیست:
Sub affiche(ByVal p As personne)
ما میتوانیم به همان آسانی بنویسیم
به عنوان
در مورد دوم، پارامتر شکلی از نوع personne در تابع affiche مقدار از نوع enseignant را خواهد گرفت. از آنجا که نوع enseignant از نوع personne مشتق شده است، این امر معتبر است.
3.2.5. تعریف مجدد و چندریختگی
بیایید رویهٔ affiche خود را تکمیل کنیم:
Sub affiche(ByVal p As personne)
' نمایش p هویت
Console.Out.WriteLine(p.identite)
End Sub
متد p.identite رشتهای را بازمیگرداند که شیء personne. را شناسایی میکند. در مثال قبلی ما، که شیء آن enseignant بود، چه اتفاقی میافتد:
Dim e As New enseignant("Lucile", "Dumas", 56, 61)
affiche(e)
بیایید به مثال زیر نگاه کنیم:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Module test
Sub Main()
' یک معلم
Dim e As New enseignant("Lucile", "Dumas", 56, 61)
affiche(e)
' یک شخص
Dim p As New personne("Jean", "Dupont", 30)
affiche(p)
End Sub
' نمایشها
Sub affiche(ByVal p As personne)
' هویت p را نمایش میدهد
Console.Out.WriteLine(p.identite)
End Sub
End Module
نتایج بهدستآمده به شرح زیر است:
Construction personne(string, string, int)
Construction enseignant(string,string,int,int)
personne(Lucile,Dumas,56)
Construction personne(string, string, int)
personne(Jean,Dupont,30)
اجرا نشان میدهد که دستور p.identite هر بار خاصیت identite از یک personne را اجرا کرد، شخصی که در e از enseignant قرار داشت، و سپس خود p از personne. این به شیء واقعی که بهعنوان پارامتر به affiche ارسال شده بود، تطبیق نیافت. ما ترجیح میدادیم که هویت کامل enseignant e را داشته باشیم. برای اینکه این اتفاق میافتاد، باید نشانه p.identite به ویژگی identite شیئی که در واقع توسط p به آن اشاره میشود، ارجاع میداد، نه به ویژگی identite بخشی "personne" از شیءای که در واقع توسط p به آن اشاره میشود. این نتیجه را میتوان با اعلام identite بهعنوان یک ویژگی قابل بازنویسی در کلاس پایه personne بهدست آورد:
Public Overridable ReadOnly Property identite() As String
Get
Return "personne(" & _prenom & "," & _nom & "," & age & ")"
End Get
End Property
کلمه کلیدی overridable، **identite را به یک ویژگی قابل جایگزینی (overridable) یا مجازی تبدیل میکند. این کلمه کلیدی را میتوان به متدها نیز اعمال کرد. کلاسهای فرزند که یک ویژگی یا متد مجازی را بازنویسی میکنند، بنابراین باید به جای **shadows از کلمه کلیدی overrides برای مشخص کردن ویژگی یا متد بازنویسیشده خود استفاده کنند. بنابراین، در کلاس enseignant، ویژگی identite به شرح زیر تعریف شده است:
' تعریف مجدد ویژگی هویت
Public Overrides ReadOnly Property identite() As String
Get
Return "enseignant(" & MyBase.identite & "," & _section & ")"
End Get
End Property
برنامهٔ آزمون:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Module test
Sub Main()
' یک معلم
Dim e As New enseignant("Lucile", "Dumas", 56, 61)
affiche(e)
' یک شخص
Dim p As New personne("Jean", "Dupont", 30)
affiche(p)
End Sub
'نمایشها
Sub affiche(ByVal p As personne)
' پوستر هویت
Console.Out.WriteLine(p.identite)
End Sub
End Module
سپس نتایج زیر را تولید میکند:
Construction personne(string, string, int)
Construction enseignant(string,string,int,int)
enseignant(personne(Lucile,Dumas,56),61)
Construction personne(string, string, int)
personne(Jean,Dupont,30)
این بار، ما با موفقیت هویت کامل معلم را بهدست آوردیم. اکنون بیایید بهجای یک ویژگی، یک متد را مجدداً تعریف کنیم. کلاس object کلاس «پدر» تمام کلاسهای VB.NET است. بنابراین وقتی مینویسیم:
در واقع بهطور ضمنی داریم مینویسیم:
کلاس object یک متد مجازی ToString را تعریف میکند:

متد ToString نام کلاسی را که شیء به آن تعلق دارد بازمیگرداند، همانطور که در مثال زیر نشان داده شده است:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Module test2
Sub Main()
' یک معلم
Console.Out.WriteLine(New enseignant("Lucile", "Dumas", 56, 61).ToString())
' یک شخص
Console.Out.WriteLine(New personne("Jean", "Dupont", 30).ToString())
End Sub
End Module
نتایج تولید شده به شرح زیر است:
Construction personne(string, string, int)
Construction enseignant(string,string,int,int)
enseignant
Construction personne(string, string, int)
personne
شایان ذکر است که اگرچه ما متد ToString را در کلاسهای personne و enseignant مجدداً تعریف نکردهایم، با این حال میتوانیم ببینیم که متد ToString در کلاس object همچنان قادر به نمایش نام واقعی کلاس شیء است. بیایید متد ToString را در کلاسهای personne و enseignant مجدداً تعریف کنیم:
' ToString
Public Overrides Function ToString() As String
' ما ویژگی «هویت» را ایجاد میکنیم
Return identite
End Function
تعریف در هر دو کلاس یکسان است. برنامهٔ آزمون زیر را در نظر بگیرید:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Module test
Sub Main()
' یک معلم
Dim e As New enseignant("Lucile", "Dumas", 56, 61)
affiche(e)
' یک شخص
Dim p As New personne("Jean", "Dupont", 30)
affiche(p)
End Sub
' نمایشها
Sub affiche(ByVal p As personne)
' پوستر هویت
Console.Out.WriteLine(p.identite)
End Sub
End Module
نتایج اجرا به شرح زیر است:
Construction personne(string, string, int)
Construction enseignant(string,string,int,int)
enseignant(personne(Lucile,Dumas,56),61)
Construction personne(string, string, int)
personne(Jean,Dupont,30)
3.3. تعریف یک ایندکسکننده برای یک کلاس
بیایید کلاس از پیش تعریفشده [ArrayList] را در پلتفرم NET در نظر بگیریم. این کلاس برای ذخیره اشیاء در یک لیست استفاده میشود. این کلاس به فضای نام [System.Collections] تعلق دارد. در مثال زیر، از این کلاس برای ذخیره فهرستی از افراد (در وسیعترین معنا) استفاده میکنیم:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Imports System.Collections
' کلاس listeDePersonnes
Public Class listeDePersonnes
Inherits ArrayList
'برای افزودن یک شخص به فهرست
Public Overloads Sub Add(ByVal p As personne)
MyBase.Add(p)
End Sub
' یک ایندکسکننده
Default Public Shadows Property Item(ByVal i As Integer) As personne
Get
Return CType(MyBase.Item(i), personne)
End Get
Set(ByVal Value As personne)
MyBase.Item(i) = Value
End Set
End Property
' شاخصگذار دیگر
Default Public Shadows ReadOnly Property Item(ByVal N As String) As Integer
Get
' جستجو برای فردی به نام N
Dim i As Integer
For i = 0 To Count - 1
If CType(Me(i), personne).nom = N Then
Return i
End If
Next i
Return -1
End Get
End Property
'toString
Public Overrides Function ToString() As String
' مقادیر (element1, element2, ..., elementn) را بازمیگرداند
Dim liste As String = "("
Dim i As Integer
' تکرار در آرایهٔ پویا
For i = 0 To (Count - 2)
liste += "[" + Me(i).ToString + "]" + ","
Next i 'for
' آخرین عنصر
If Count <> 0 Then
liste += "[" + Me(i).ToString + "]"
End If
liste += ")"
Return liste
End Function
End Class
بیایید به برخی از ویژگیها و متدهای کلاس [ArrayList] نگاهی بیندازیم:
ویژگی که تعداد عناصر موجود در لیست را نشان میدهد | |
متد برای افزودن یک شیء به لیست | |
متدی که عنصر i-ام لیست را برمیگرداند |
توجه داشته باشید که برای بازیابی عنصر i-ام لیست، ما به جای [liste.Item(i)]، مستقیماً [liste(i)] را نوشتهایم که در نگاه اول نادرست به نظر میرسد. با این حال این کار ممکن است زیرا کلاس [ArrayList] یک ویژگی پیشفرض [Item] را با نحوهای مشابه زیر تعریف میکند:
Default Public Property Item(ByVal i As Integer) As Object
Get
...
End Get
Set(ByVal Value As personne)
...
End Set
End Property
وقتی کامپایلر با نشانه [liste(i)] مواجه میشود، بررسی میکند که آیا کلاس [ArrayList] خاصیتی با امضای زیر تعریف کرده است:
Default Public Property Proc(ByVal var As Integer) As Type
در اینجا، رویه [Item] را پیدا خواهد کرد. سپس نشانه [liste(i)] را به [liste.Item(i)] تبدیل خواهد کرد. ویژگی [Item] بهعنوان ویژگی شاخصگذاریشدهٔ پیشفرض کلاس [ArrayList] شناخته میشود. اجرای برنامهٔ فوق نتایج زیر را تولید میکند:
dos>vbc /r:personne.dll /r:enseignant.dll lstpersonnes1.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
dos>dir
11/03/2004 18:26 3 584 enseignant.dll
12/03/2004 15:34 3 584 lstpersonnes1.exe
12/03/2004 13:39 661 lstpersonnes1.vb
11/03/2004 18:26 4 096 personne.dll
dos>lstpersonnes1
Construction personne(string, string, int)
Construction personne(string, string, int)
Construction personne(string, string, int)
Construction enseignant(string,string,int,int)
personne(paul,chenou,31)
personne(nicole,chenou,11)
enseignant(personne(jacques,sileau,33),61)
بیایید یک کلاس به نام [listeDePersonnes] ایجاد کنیم که شامل فهرستی از افراد باشد – نوع خاصی از فهرست که به نظر میرسد بهطور طبیعی از کلاس [ArrayList] مشتق شود:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Imports System.Collections
' کلاس listeDePersonnes
Public Class listeDePersonnes
Inherits ArrayList
' برای افزودن یک شخص به فهرست
Public Shadows Sub Add(ByVal p As Object)
' p باید یک شخص باشد
If Not TypeOf (p) Is personne Then
Throw New Exception("L'objet ajouté (" + p.ToString + ") n'est pas une personne")
Else
MyBase.Add(p)
End If
End Sub
' یک نمایه ساز
Default Public Shadows Property Index(ByVal i As Integer) As personne
Get
Return CType(MyBase.Item(i), personne)
End Get
Set(ByVal Value As personne)
MyBase.Item(i) = Value
End Set
End Property
' toString
Public Overrides Function ToString() As String
' مقادیر (element1, element2, ..., elementn) را بازمیگرداند
Dim liste As String = "("
Dim i As Integer
' ما روی آرایهٔ پویا حلقهزنی میکنیم
For i = 0 To (Count - 2)
liste += "[" + Me(i).ToString + "]" + ","
Next i 'for
' آخرین عنصر
If Count <> 0 Then
liste += "[" + Me(i).ToString + "]"
End If
liste += ")"
Return liste
End Function
End Class
این کلاس دارای متدها و ویژگیهای زیر است:
یک رشته را بازمیگرداند که «نماینده» محتوای لیست است | |
یک متد برای افزودن یک شخص به لیست | |
ویژگی پیشفرض فهرستشده که فرد i-ام را در لیست بازمیگرداند |
بیایید ویژگیهای جدید را بررسی کنیم:
یک متد جدید به نام [Add] ایجاد شده است.
' برای افزودن یک شخص به لیست
Public Shadows Sub Add(ByVal p As Object)
'p باید یک شخص باشد
If Not TypeOf (p) Is personne Then
Throw New Exception("L'objet ajouté (" + p.ToString + ") n'est pas une personne")
Else
MyBase.Add(p)
End If
End Sub
متدی با همین امضا در کلاس والد [ArrayList] وجود دارد؛ بنابراین از کلمه کلیدی [Shadows] استفاده میشود تا نشان دهد که رویه جدید جایگزین رویه موجود در کلاس والد است. متد [Add] در کلاس فرزند بررسی میکند که شیء افزودهشده واقعاً از نوع [personne] است یا از آن ارثبری شده است، با استفاده از تابع [TypeOf]. اگر اینطور نباشد، با استفاده از دستور [Throw] یک استثنا پرتاب میشود. اگر شیء در حال اضافه شدن واقعاً از نوع [personne] باشد، از متد [Add] کلاس پایه برای انجام افزودن استفاده میشود.
یک ویژگی شاخصگذاریشده ایجاد میشود:
' شاخصساز
Default Public Shadows Property Index(ByVal i As Integer) As personne
Get
Return CType(MyBase.Item(i), personne)
End Get
Set(ByVal Value As personne)
MyBase.Item(i) = Value
End Set
End Property
در کلاس پایه، از قبل یک ویژگی پیشفرض به نام [Item] با همان امضا وجود دارد. بنابراین ما مجبوریم از کلمه کلیدی [Shadows] استفاده کنیم تا نشان دهیم که ویژگی جدید فهرستشده [Index]، ویژگی موجود در کلاس پایه، [Item] را «پنهان» خواهد کرد. توجه داشته باشید که این موضوع حتی زمانی که دو خاصیت نام یکسانی ندارند نیز صادق است. ویژگی [Index] برای ارجاع به شماره فرد i در لیست استفاده میشود. این ویژگی برای دسترسی به عنصر شماره i از شی زیرین [ArrayList]، به ویژگی [Item] از کلاس پایه متکی است. تغییرات نوع برای در نظر گرفتن این واقعیت اعمال میشود که ویژگی [Item] با عناصر از نوع [Object] کار میکند، در حالی که ویژگی [Index] با عناصر از نوع [personne] کار میکند.
در نهایت، ما متد [ToString] از کلاس [ArrayList] را بازنویسی میکنیم:
' toString
Public Overrides Function ToString() As String
' مقادیر (element1, element2, ..., elementn) را بازمیگرداند
Dim liste As String = "("
Dim i As Integer
' ما روی آرایهٔ پویا حلقه میزنیم
For i = 0 To (Count - 2)
liste += "[" + Me(i).ToString + "]" + ","
Next i 'for
' آخرین عنصر
If Count <> 0 Then
liste += "[" + Me(i).ToString + "]"
End If
liste += ")"
Return liste
End Function
این متد یک رشته از نوع «(e1, e2, …, en)» را بازمیگرداند، که در آن e1، e2، …، en عناصر لیست هستند. توجه داشته باشید به قرارداد [Me(i)] که به عنصر شماره i از شیء فعلی [Me] اشاره میکند. از خاصیت فهرستشده پیشفرض استفاده میشود. بنابراین، [Me(i)] معادل [Me.Index(i)] است.
کد کلاس در فایل [lstpersonnes2.vb] قرار داده شده و کامپایل میشود:
dos>dir
11/03/2004 18:26 3 584 enseignant.dll
12/03/2004 15:45 970 lstpersonnes2.vb
11/03/2004 18:26 4 096 personne.dll
dos>vbc /r:personne.dll /r:enseignant.dll /t:library lstpersonnes2.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
dos>dir
11/03/2004 18:26 3 584 enseignant.dll
12/03/2004 15:50 3 584 lstpersonnes2.dll
12/03/2004 15:45 970 lstpersonnes2.vb
11/03/2004 18:26 4 096 personne.dll
یک برنامه آزمون ایجاد میشود:
' گزینهها
Option Explicit On
Option Strict On
' فضاهای نام
Imports System
Imports System.Collections
Module test
Sub Main()
' ایجاد یک لیست خالی از افراد
Dim liste As listeDePersonnes = New listeDePersonnes
' ایجاد افراد
Dim p1 As personne = New personne("paul", "chenou", 31)
Dim p2 As personne = New personne("nicole", "chenou", 11)
Dim e1 As enseignant = New enseignant("jacques", "sileau", 33, 61)
' پر کردن فهرست
liste.Add(p1)
liste.Add(p2)
liste.Add(e1)
' نمایش لیست
Console.Out.WriteLine(liste.ToString)
' افزودن یک شی غیرانسانی
Try
liste.Add(4)
Catch e As Exception
Console.Error.WriteLine(e.Message)
End Try
End Sub
End Module
کامپایل میشود:
dos>vbc /r:personne.dll /r:enseignant.dll /r:lstpersonnes2.dll test.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
dos>dir
11/03/2004 18:26 3 584 enseignant.dll
12/03/2004 15:50 3 584 lstpersonnes2.dll
12/03/2004 15:45 970 lstpersonnes2.vb
11/03/2004 18:26 4 096 personne.dll
12/03/2004 15:50 3 584 test.exe
12/03/2004 15:49 623 test.vb
سپس اجرا شد:
dos>test
Construction personne(string, string, int)
Construction personne(string, string, int)
Construction personne(string, string, int)
Construction enseignant(string,string,int,int)
([personne(paul,chenou,31)],[personne(nicole,chenou,11)],[enseignant(personne(jacques,sileau,33),61)])
L'objet ajouté (4) n'est pas une personne
ممکن است بخواهید بنویسید
که در آن l از نوع [listeDePersonnes] خواهد بود. در اینجا میخواهیم فهرست l را نه با شماره عنصر بلکه با نام شخص ایندکس کنیم. برای این کار، یک ویژگی جدید را بهصورت پیشفرض ایندکسشده تعریف میکنیم:
' شاخصگذار دیگر
Default Public Shadows ReadOnly Property Item(ByVal N As String) As Integer
Get
'جستجو برای شخص با نام N
Dim i As Integer
For i = 0 To Count - 1
If CType(Me(i), personne).nom = N Then
Return i
End If
Next i
Return -1
End Get
End Property
خط اول
Default Public Shadows ReadOnly Property Index(ByVal N As String) As Integer
نشان میدهد که ما در حال ایجاد یک ویژگی پیشفرض نمایهشده جدید هستیم. تمام ویژگیهای پیشفرض باید نام یکسانی داشته باشند، در این مورد [Index]. ویژگی جدید [Index] کلاس listeDePersonnes را با رشته کاراکتری N نمایه میکند. نتیجه listeDePersonnes(N) یک عدد صحیح است. این عدد صحیح، موقعیت شخص با نام N در لیست خواهد بود، یا در صورتی که آن شخص در لیست نباشد، مقدار -1 را برمیگرداند. فقط خاصیت get تعریف شده است، و بدین ترتیب از استفاده از listeDePersonnes جلوگیری میکند (استفاده از "nom")=valeur مستلزم تعریف خاصیت set بود). از این رو کلمه کلیدی [ReadOnly]. کلمه کلیدی [Shadows] برای پنهان کردن ویژگی پیشفرض کلاس پایه لازم است (هرچند که امضای یکسانی ندارد).
در بدنه get، لیست افراد برای یافتن نام N که بهعنوان پارامتر ارسال شده است، جستجو میشود. اگر در موقعیت i یافت شود، i بازگردانده میشود؛ در غیر این صورت، -1 بازگردانده میشود.
یک برنامه آزمایشی جدید میتواند به شکل زیر باشد:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
' صفحه آزمایشی
Module test
Sub Main()
' فهرستی از افراد
Dim l As New listeDePersonnes
' افزودن افراد
l.Add(New personne("jean", "dumornet", 10))
l.Add(New personne("pauline", "duchemin", 12))
' نمایش
Console.Out.WriteLine(("l=" + l.ToString))
l.Add(New personne("jacques", "tartifume", 27))
Console.Out.WriteLine(("l=" + l.ToString))
' تغییر آیتم ۱
l(1) = New personne("sylvie", "cachan", 5)
'نمایش آیتم 1
Console.Out.WriteLine(("l[1]=" + l(1).ToString))
' نمایش لیست l
Console.Out.WriteLine(("l=" + l.ToString))
' جستجوی افراد
Dim noms() As String = New [String]() {"cachan", "inconnu"}
Dim i As Integer
For i = 0 To noms.Length - 1
Dim inom As Integer = l(noms(i))
If inom <> -1 Then
Console.Out.WriteLine(("personne(" & noms(i) & ")=" & l(inom).ToString))
Else
Console.Out.WriteLine(("personne(" + noms(i) + ") n'existe pas"))
End If
Next i
End Sub
End Module
اجرا نتایج زیر را تولید میکند:
personne(string, string, int)
Construction personne(string, string, int)
l=([personne(jean,dumornet,10)],[personne(pauline,duchemin,12)])
Construction personne(string, string, int)
l=([personne(jean,dumornet,10)],[personne(pauline,duchemin,12)],[personne(jacques,tartifume,27)])
Construction personne(string, string, int)
l[1]=personne(sylvie,cachan,5)
l=([personne(jean,dumornet,10)],[personne(sylvie,cachan,5)],[personne(jacques,tartifume,27)])
personne(cachan)=personne(sylvie,cachan,5)
personne(inconnu) n'existe pas
3.4. ساختارها
ساختار VB.NET مستقیماً از ساختار زبان C مشتق شده و شباهت زیادی به یک کلاس دارد. یک ساختار به صورت زیر تعریف میشود:
Structure spersonne
' ویژگیها
...
' ویژگیها
...
' سازندهها
...
' روشها
End Structure
با وجود شباهتها در نحو، تفاوتهای قابل توجهی بین کلاسها و ساختارها وجود دارد. برای مثال، مفهوم ارثبری در ساختارها وجود ندارد. اگر در حال نوشتن کلاسی هستیم که قرار نیست از کلاسی دیگر مشتق شود، چه تفاوتهایی بین ساختارها و کلاسها وجود دارد که به ما در انتخاب بین این دو کمک کند؟ بیایید برای پی بردن به این موضوع، از مثال زیر استفاده کنیم:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
'ساختار spersonne
Structure spersonne
Public nom As String
Public age As Integer
End Structure
' کلاس `cpersonne`
Class cpersonne
Public nom As String
Public age As Integer
End Class
' یک ماژول آزمایشی
Public Module test
Sub Main()
' یک شخص p1
Dim sp1 As spersonne
sp1.nom = "paul"
sp1.age = 10
Console.Out.WriteLine(("sp1=spersonne(" & sp1.nom & "," & sp1.age & ")"))
' یک شخص p2
Dim sp2 As spersonne = sp1
Console.Out.WriteLine(("sp2=spersonne(" & sp2.nom & "," & sp2.age & ")"))
'sp2 اصلاح شده است
sp2.nom = "nicole"
sp2.age = 30
'تأیید sp1 و sp2
Console.Out.WriteLine(("sp1=cpersonne(" & sp1.nom & "," & sp1.age & ")"))
Console.Out.WriteLine(("sp2=cpersonne(" & sp2.nom & "," & sp2.age & ")"))
' یک شخص cp1
Dim cp1 As New cpersonne
cp1.nom = "paul"
cp1.age = 10
Console.Out.WriteLine(("cP1=cpersonne(" & cp1.nom & "," & cp1.age & ")"))
' یک cperson P2
Dim cp2 As cpersonne = cp1
Console.Out.WriteLine(("cP2=cpersonne(" & cp2.nom & "," & cp2.age & ")"))
' P2 اصلاح شده است
cp2.nom = "nicole"
cp2.age = 30
'تأیید P1 و P2
Console.Out.WriteLine(("cP1=cpersonne(" & cp1.nom & "," & cp1.age & ")"))
Console.Out.WriteLine(("cP2=cpersonne(" & cp2.nom & "," & cp2.age & ")"))
End Sub
End Module
اگر این برنامه را اجرا کنید، نتایج زیر را دریافت میکنید:
sp1=spersonne(paul,10)
sp2=spersonne(paul,10)
sp1=cpersonne(paul,10)
sp2=cpersonne(nicole,30)
cP1=cpersonne(paul,10)
cP2=cpersonne(paul,10)
cP1=cpersonne(nicole,30)
cP2=cpersonne(nicole,30)
در حالی که در صفحات قبلی این فصل از کلاس personne استفاده کردیم، اکنون از ساختار spersonne استفاده میکنیم:
'ساختار شخص
Structure spersonne
Public nom As String
Public age As Integer
End Structure
اعلامیه
Dim sp1 As spersonne
یک ساختار (نام، سن) ایجاد میکند و مقدار sp1 خود این ساختار است.
اعلام
Dim cp1 As New cpersonne
یک شیء [cpersonne] (تقریباً معادل ساختار ما) ایجاد میکند و cp1 سپس آدرس (اشاره) این شیء است.
خلاصه
- در مورد ساختار، مقدار sp1 خودِ ساختار است
- در مورد کلاس، مقدار p1 نشانی شیء ایجادشده است
![]() |
![]() |
وقتی موارد زیر در برنامه نوشته میشود
Dim sp2 As spersonne = sp1
یک ساختار جدید (name, age) ایجاد شده و با مقدار p1، یعنی خود ساختار، مقداردهی اولیه میشود.
![]() |
بنابراین ساختار در sp1 در sp2 کپی میشود. این یک کپی به صورت مقدار است.
دستور
Dim cp2 As cpersonne = cp1
به شکل متفاوتی عمل میکند. مقدار cp1 به cp2 کپی میشود، اما از آنجا که این مقدار در واقع نشانی شیء است، خود شیء کپی نمیشود. این شیء صرفاً دو مرجع دارد که به آن اشاره میکنند:
![]() |
در مورد ساختار، اگر مقدار sp2 تغییر کند، مقدار sp1 تغییر نمیکند، همانطور که در برنامه نشان داده شده است. در مورد شیء، اگر شیئی که توسط cp2 به آن اشاره میشود تغییر یابد، آنی که توسط QZXX2HTMLP000650ZQX به آن اشاره میشود نیز تغییر مییابد، زیرا آنها یکی هستند. این موضوع نیز توسط نتایج برنامه اثبات میشود.
بنابراین میتوانیم از این توضیحات نتیجه بگیریم که:
- مقدار یک متغیر از نوع «ساختار» خودِ ساختار است
- مقدار یک متغیر از نوع 'object' نشانی شیئی است که به آن اشاره میکند
هنگامی که این تفاوت اساسی درک شود، ساختار بسیار شبیه به یک کلاس از آب میآید، همانطور که مثال جدید زیر نشان میدهد:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
'ساختار شخص
Structure personne
' ویژگیها
Private _nom As String
Private _age As Integer
' ویژگیها
Public Property nom() As String
Get
Return _nom
End Get
Set(ByVal Value As String)
_nom = value
End Set
End Property
Public Property age() As Integer
Get
Return _age
End Get
Set(ByVal Value As Integer)
_age = value
End Set
End Property
' سازنده
Public Sub New(ByVal NOM As String, ByVal AGE As Integer)
_nom = NOM
_age = AGE
End Sub 'New
' TOSTRING
Public Overrides Function ToString() As String
Return "personne(" & nom & "," & age & ")"
End Function
End Structure
' یک ماژول آزمایشی
Module test
Sub Main()
' یک شخص p1
Dim p1 As New personne("paul", 10)
Console.Out.WriteLine(("p1=" & p1.ToString))
' یک شخص p2
Dim p2 As personne = p1
Console.Out.WriteLine(("p2=" & p2.ToString))
' p2 اصلاح شده است
p2.nom = "nicole"
p2.age = 30
'بررسی p1 و p2
Console.Out.WriteLine(("p1=" & p1.ToString))
Console.Out.WriteLine(("p2=" & p2.ToString))
End Sub
End Module
نتایج اجرای زیر به دست میآیند:
تنها تفاوت قابل توجه در اینجا بین یک ساختار و یک کلاس این است که در مورد کلاس، اشیاء p1 و p2 در پایان برنامه دارای یک مقدار یکسان، یعنی مقدار p2، خواهند بود.
3.5. رابطها
یک رابط مجموعهای از پروتوتایپهای متد یا خاصیت است که یک قرارداد را تشکیل میدهد. کلاسی که تصمیم میگیرد یک رابط را پیادهسازی کند، متعهد میشود که پیادهسازی تمام متدهای تعریفشده در آن رابط را فراهم کند. کامپایلر این پیادهسازی را بررسی میکند. در اینجا، بهعنوان مثال، تعریف رابط Istats را مشاهده میکنید:
هر کلاسی که این رابط را پیادهسازی کند، به صورت زیر اعلام خواهد شد:
public class C
Implements Istats
...
function moyenne() as Double Implements Istats.moyenne
...
end function
function écartType () as Double Implements Istats. écartType
...
end function
end class
متدهای [moyenne] و [écartType] باید در کلاس C تعریف شوند. کد زیر را در نظر بگیرید:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
'ساختار
Public Structure élève
Public _nom As String
Public _note As Double
'سازنده
Public Sub New(ByVal NOM As String, ByVal NOTE As Double)
Me._nom = NOM
Me._note = NOTE
End Sub
End Structure
' کلاس یادداشتها
Public Class notes
' ویژگی
Protected _matière As String
Protected _élèves() As élève
' تولیدکننده
Public Sub New(ByVal MATIERE As String, ByVal ELEVES() As élève)
' سوابق دانشآموز و درس
Me._matière = MATIERE
Me._élèves = ELEVES
End Sub
' ToString
Public Overrides Function ToString() As String
Dim valeur As String = "matière=" + _matière + ", notes=("
Dim i As Integer
' ادغام تمام نمرات
For i = 0 To (_élèves.Length - 1) - 1
valeur &= "[" & _élèves(i)._nom & "," & _élèves(i)._note & "],"
Next i
'نمره نهایی
If _élèves.Length <> 0 Then
valeur &= "[" & _élèves(i)._nom & "," & _élèves(i)._note & "]"
End If
valeur += ")"
' پایان
Return valeur
End Function
End Class
کلاس notes نشانها را برای یک کلاس در یک موضوع گرد هم میآورد:
Public Class notes
' ویژگی
Protected _matière As String
Protected _élèves() As élève
ویژگیها به صورت protected اعلام شدهاند تا از یک کلاس مشتقشده قابل دسترسی باشند. نوع élève یک ساختار است که نام دانشآموز و نمره او را در آن درس ذخیره میکند:
Public Structure élève
Public _nom As String
Public _note As Double
' سازنده
Public Sub New(ByVal NOM As String, ByVal NOTE As Double)
Me._nom = NOM
Me._note = NOTE
End Sub
End Structure
ما تصمیم گرفتهایم این کلاس، notes، را به کلاسی، notesStats، مشتق کنیم که دو ویژگی اضافی خواهد داشت: میانگین و انحراف معیار نمرات:
Public Class notesStats
Inherits notes
Implements Istats
'ویژگیها
Private _moyenne As Double
Private _écartType As Double
کلاس notesStats رابط زیر Istats را پیادهسازی میکند:
این بدان معناست که کلاس notesStats باید دارای دو متد به نامهای moyenne و écartType با امضای مشخصشده در رابط Istats باشد. کلاس notesStats به شرح زیر است:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Public Class notesStats
Inherits notes
Implements Istats
' ویژگیها
Private _moyenne As Double
Private _écartType As Double
' سازنده
Public Sub New(ByVal MATIERE As String, ByVal ELEVES() As élève)
MyBase.New(MATIERE, ELEVES)
'محاسبه نمره میانگین
Dim somme As Double = 0
Dim i As Integer
For i = 0 To ELEVES.Length - 1
somme += ELEVES(i)._note
Next i
If ELEVES.Length <> 0 Then
_moyenne = somme / ELEVES.Length
Else
_moyenne = -1
End If
' انحراف معیار
Dim carrés As Double = 0
For i = 0 To ELEVES.Length - 1
carrés += Math.Pow(ELEVES(i)._note - _moyenne, 2)
Next i
If ELEVES.Length <> 0 Then
_écartType = Math.Sqrt((carrés / ELEVES.Length))
Else
_écartType = -1
End If
End Sub
' ToString
Public Overrides Function ToString() As String
Return MyBase.ToString() & ",moyenne=" & _moyenne & ",écart-type=" & _écartType
End Function 'ToString
'روشهای رابط Istats
Public Function moyenne() As Double Implements Istats.moyenne
'میانگین نمرات را محاسبه میکند
Return _moyenne
End Function
Public Function écartType() As Double Implements Istats.écartType
'انحراف معیار را بازمیگرداند
Return _écartType
End Function
End Class
میانگین _moyenne و انحراف معیار _ecartType به محض ایجاد شیء محاسبه میشوند. بنابراین، متدهای moyenne و écartType به سادگی مقادیر ویژگیهای _moyenne و _ecartType را بازمیگردانند. هر دو متد در صورتی که آرایهٔ دانشآموزان خالی باشد، مقدار -1 را بازمیگردانند.
کلاس تست زیر:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Module test
Sub Main()
' برخی دانشآموزان و نمرات
Dim ELEVES() As élève = {New élève("paul", 14), New élève("nicole", 16), New élève("jacques", 18)}
'که در یک شیء «marks» ذخیره شدهاند
Dim anglais As New notes("anglais", ELEVES)
' و که نمایش داده میشوند
Console.Out.WriteLine((anglais.ToString))
' همان، با میانگین و انحراف معیار
anglais = New notesStats("anglais", ELEVES)
Console.Out.WriteLine((anglais.ToString))
End Sub
End Module
نتایج زیر را تولید میکند:
matière=anglais, notes=([paul,14],[nicole,16],[jacques,18])
matière=anglais, notes=([paul,14],[nicole,16],[jacques,18]),moyenne=16,écart-type=1,63299316185545
کلاس notesStats میتوانست به راحتی متدهای moyenne و écartType را برای خود پیادهسازی کند، بدون اینکه مشخص کند که رابط Istats را پیادهسازی میکند. هدف از رابطها چیست؟ هدف به این صورت است: یک تابع میتواند بهعنوان پارامتر صوری، مقداری از نوع یک رابط I را بپذیرد. هر شیء از کلاس C که رابط I را پیادهسازی کند، میتواند سپس بهعنوان پارامتر حقیقی به آن تابع ارسال شود. مثال زیر را در نظر بگیرید:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
'یک رابط Iexample
Public Interface Iexemple
Function ajouter(ByVal i As Integer, ByVal j As Integer) As Integer
Function soustraire(ByVal i As Integer, ByVal j As Integer) As Integer
End Interface
' یک کلاس اول
Public Class classe1
Implements Iexemple
Public Function ajouter(ByVal a As Integer, ByVal b As Integer) As Integer Implements Iexemple.ajouter
Return a + b + 10
End Function
Public Function soustraire(ByVal a As Integer, ByVal b As Integer) As Integer Implements Iexemple.soustraire
Return a - b + 20
End Function
End Class
'یک کلاس دوم
Public Class classe2
Implements Iexemple
Public Function ajouter(ByVal a As Integer, ByVal b As Integer) As Integer Implements Iexemple.ajouter
Return a + b + 100
End Function
Public Function soustraire(ByVal a As Integer, ByVal b As Integer) As Integer Implements Iexemple.soustraire
Return a - b + 200
End Function
End Class
رابط Iexemple دو متد را تعریف میکند: ajouter و soustraire. کلاسهای classe1 و classe2 این رابط را پیادهسازی میکنند. توجه داشته باشید که این کلاسها کار دیگری انجام نمیدهند؛ این کار برای ساده نگهداشتن مثال است. اکنون مثال زیر را در نظر بگیرید:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
'کلاس آزمایشی
Module test
'محاسبه
Sub calculer(ByVal i As Integer, ByVal j As Integer, ByVal inter As Iexemple)
Console.Out.WriteLine(inter.ajouter(i, j))
Console.Out.WriteLine(inter.soustraire(i, j))
End Sub
' تابع Main
Sub Main()
' ایجاد دو شیء، class1 و class2
Dim c1 As New classe1
Dim c2 As New classe2
' فراخوانی تابع استاتیک 'calculate'
calculer(4, 3, c1)
calculer(14, 13, c2)
End Sub
End Module
تابع calculer یک عنصر از نوع Iexemple را به عنوان پارامتر میپذیرد. بنابراین این تابع میتواند برای این پارامتر یک شیء از نوع classe1 و همچنین یک شیء از نوع classe2 را بپذیرد. این کاری است که در رویه Main انجام میشود، با نتایج زیر:
بنابراین میتوانیم ببینیم که این یک ویژگی مشابه چندریختی (polymorphism) مشاهدهشده در کلاسها است. اگر مجموعهای از کلاسهای Ci که از طریق ارثبری به یکدیگر مرتبط نیستند (و بنابراین نمیتوانیم از چندریختی مبتنی بر ارثبری استفاده کنیم) مجموعهای از متدها با امضای یکسان را به اشتراک بگذارند، ممکن است مفید باشد که این متدها را در یک رابط (interface) به نام I گروهبندی کنیم که همه کلاسهای مرتبط از آن ارثبری کنند. اشیاء این کلاسهای Ci سپس میتوانند بهعنوان پارامتر برای توابعی که پارامتری از نوع I میپذیرند، استفاده شوند، c.a.d. این توابع تنها از متدهای اشیاء Ci که در رابط I تعریف شدهاند استفاده میکنند و نه از ویژگیها و متدهای خاص کلاسهای مختلف Ci. در نهایت، توجه داشته باشید که ارثبری چندگانه از اینترفیس امکانپذیر است، c.a.d. ما میتوانیم بنویسیم
Public Class classe
Implements I1,I2,...
که در آن Ij اینترفیسها هستند.
3.6. فضاهای نام
برای نوشتن یک خط روی صفحه، از دستور
اگر به تعریف کلاس Console نگاه کنیم
Namespace: System
Assembly: Mscorlib (in Mscorlib.dll)
متوجه میشویم که به فضای نام System تعلق دارد. این بدان معناست که کلاس Console باید به عنوان System.Console ارجاع داده شود، و در واقع باید بنویسیم:
میتوان با استفاده از یک بند imports از این مشکل جلوگیری کرد:
ما میگوییم که با استفاده از بند imports، فضای نام System را وارد میکنیم. وقتی کامپایلر با نام یک کلاس (در این مورد، Console) مواجه میشود، آن را در فضاهای نام مختلف واردشده توسط بندهای imports جستجو میکند. در اینجا، کلاس Console را در فضای نام System پیدا خواهد کرد. اکنون بیایید به دومین اطلاعات مرتبط با کلاس Console توجه کنیم:
Assembly: Mscorlib (in Mscorlib.dll)
این خط نشان میدهد که تعریف کلاس Console در کدام «اسمبلی» قرار دارد. هنگام کامپایل خارجی Studio.NET و زمانی که نیاز دارید ارجاعات به فایلهای مختلف dll را که حاوی کلاسهای مورد نیاز شما هستند، مشخص کنید، این اطلاعات میتواند مفید باشد. به خاطر داشته باشید که برای ارجاع به فایلهای dll مورد نیاز برای کامپایل یک کلاس، مینویسید:
هنگام ایجاد یک کلاس، میتوان آن را در داخل یک فضای نام ایجاد کرد. هدف از این نامفضاها، جلوگیری از تداخل نام بین کلاسها هنگام فروش آنها است. برای مثال، دو شرکت E1 و E2 را در نظر بگیرید که به ترتیب کلاسهایی را در dll بستهبندی و توزیع میکنند، E1.dll و E2.dll بهترتیب. فرض کنیم مشتری C این دو مجموعه کلاس را خریداری میکند که در هر دو شرکت کلاسی به نام personne تعریف شده است. مشتری C برنامهای را به شرح زیر کامپایل میکند:
اگر سورس prog.vb از کلاس personne استفاده کند، کامپایلر نخواهد دانست که آیا باید از کلاس personne در E1.dll استفاده کند یا از کلاس موجود در E2.dll. این امر منجر به خطا خواهد شد. اگر شرکت E1 دقت کند که کلاسهای خود را در یک فضای نام به نام E1 ایجاد کند و شرکت E2 در یک فضای نام به نام E2، دو کلاس personne سپس با نامهای E1.personne و E2.personne نامگذاری خواهند شد. کلاینت باید در کلاسهای خود از E1.personne یا E2.personne استفاده کند، اما نه از personne. فضای نام این ابهام را برطرف میکند. برای ایجاد یک کلاس در یک فضای نام، به این صورت مینویسند:
Namespace istia.st
Public Class personne
'تعریف کلاس
...
end Class
end Namespace
برای مثال، بیایید کلاس personne را که قبلاً دربارهاش بحث کردیم، در یک فضای نام ایجاد کنیم. ما istia.st را بهعنوان فضای نام انتخاب میکنیم. کلاس personne به این صورت درمیآید:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
' ایجاد فضای نام istia.st
Namespace istia.st
Public Class personne
' ویژگیها
Private prenom As String
Private nom As String
Private age As Integer
' روش
Public Sub initialise(ByVal P As String, ByVal N As String, ByVal age As Integer)
Me.prenom = P
Me.nom = N
Me.age = age
End Sub
' روش
Public Sub identifie()
Console.Out.WriteLine((prenom & "," & nom & "," & age))
End Sub
End Class
End Namespace
این کلاس به personne.dll کامپایل میشود:
dos>vbc /t:library personne.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
اکنون بیایید کلاس personne را در یک کلاس تست استفاده کنیم:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Imports istia.st
' صفحه آزمایشی
Public Module test
Sub Main()
Dim p1 As New personne
p1.initialise("Jean", "Dupont", 30)
p1.identifie()
End Sub
End Module
برای جلوگیری از نوشتن
Dim p1 As New istia.st.personne
ما با استفاده از یک بند imports، فضای نام istia.st را وارد کردهایم:
Imports istia.st
اکنون برنامهٔ آزمایشی را کامپایل کنیم:
dos>dir
12/03/2004 18:06 3 584 personne.dll
11/03/2004 18:27 610 personne.vb
12/03/2004 18:05 254 test.vb
dos>vbc /r:personne.dll test.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
dos>dir
12/03/2004 18:06 3 584 personne.dll
11/03/2004 18:27 610 personne.vb
12/03/2004 18:08 3 072 test.exe
12/03/2004 18:05 254 test.vb
این یک فایل به نام test.exe تولید میکند که با اجرای آن، نتایج زیر به دست میآید:
3.7. مثال IMPOTS
ما به محاسبه مالیات که پیشتر در فصل قبل پوشش داده شده بود بازمیگردیم و آن را با استفاده از یک کلاس پردازش میکنیم. بیایید مسئله را مرور کنیم:
ما مورد سادهشدهی یک مؤدی را در نظر میگیریم که تنها حقوق خود را برای اظهارنامه دارد:
- تعداد سهام کارمند را به صورت nbParts = nbEnfants/2 + 1 در صورتی که متأهل نباشد، محاسبه میکنیم، nbEnfants/2 + 2 اگر متأهل باشند، که در آن nbEnfants تعداد فرزندان اوست.
- اگر او حداقل سه فرزند داشته باشد، مستحق دریافت نیم سهم اضافی است.
- درآمد مشمول مالیات او به صورت R = 0.72 × S محاسبه میشود، که در آن S حقوق سالانه او است
- ضریب خانوادگی او به صورت QF = R / nbParts محاسبه میشود
- مالیات I او محاسبه میشود. جدول زیر را در نظر بگیرید:
۱۲٬۶۲۰٫۰ | 0 | 0 |
۱۳٬۱۹۰ | 0.05 | ۶۳۱ |
15,640 | 0.1 | ۱٬۲۹۰٫۵ |
۲۴٬۷۴۰ | 0.15 | ۲٬۰۷۲٫۵ |
۳۱٬۸۱۰ | 0.2 | ۳٬۳۰۹٫۵ |
۳۹٬۹۷۰ | 0.25 | ۴٬۹۰۰ |
۴۸٬۳۶۰ | 0.3 | ۶۸۹۸.۵ |
۵۵٬۷۹۰ | 0.35 | ۹٬۳۱۶٫۵ |
۹۲٬۹۷۰ | 0.4 | ۱۲٬۱۰۶ |
۱۲۷٬۸۶۰ | 0.45 | ۱۶٬۷۵۴٫۵ |
۱۵۱٬۲۵۰ | 0.50 | ۲۳٬۱۴۷٫۵ |
۱۷۲٬۰۴۰ | 0.55 | ۳۰٬۷۱۰ |
۱۹۵٬۰۰۰ | 0.60 | ۳۹٬۳۱۲ |
0 | 0.65 | ۴۹٬۰۶۲ |
هر سطر دارای ۳ فیلد است. برای محاسبه مالیات I، به دنبال اولین سطری میگردیم که QF ≤ field1 باشد. برای مثال، اگر QF = 23000 باشد، سطر را پیدا خواهیم کرد
مالیه I در این صورت برابر است با 0.15*R - 2072.5*nbParts. اگر QF به گونهای باشد که شرط QF <= field1 هرگز برقرار نشود، ضرایب مربوط به آخرین خط استفاده میشوند. در این صورت:
که مالیات I را به صورت 0.65*R - 49062*nbParts تعیین میکند.
کلاس «impot» به صورت زیر تعریف خواهد شد:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Public Class impot
'دادههای مورد نیاز برای محاسبه مالیات
'از یک منبع خارجی تأمین میشود
Private limites(), coeffR(), coeffN() As Decimal
' تولیدکننده
Public Sub New(ByVal LIMITES() As Decimal, ByVal COEFFR() As Decimal, ByVal COEFFN() As Decimal)
' ما بررسی میکنیم که سه جدول اندازه یکسانی داشته باشند
Dim OK As Boolean = LIMITES.Length = COEFFR.Length And LIMITES.Length = COEFFN.Length
If Not OK Then
Throw New Exception("Les 3 tableaux fournis n'ont pas la même taille(" & LIMITES.Length & "," & COEFFR.Length & "," & COEFFN.Length & ")")
End If
'همهچیز خوب است
Me.limites = LIMITES
Me.coeffR = COEFFR
Me.coeffN = COEFFN
End Sub
'محاسبه مالیات
Public Function calculer(ByVal marié As Boolean, ByVal nbEnfants As Integer, ByVal salaire As Long) As Long
' تعداد سهام را محاسبه کنید
Dim nbParts As Decimal
If marié Then
nbParts = CDec(nbEnfants) / 2 + 2
Else
nbParts = CDec(nbEnfants) / 2 + 1
End If
If nbEnfants >= 3 Then
nbParts += 0.5D
End If
'محاسبه درآمد مشمول مالیات و ضریب خانوادگی
Dim revenu As Decimal = 0.72D * salaire
Dim QF As Decimal = revenu / nbParts
'محاسبه مالیات
limites((limites.Length - 1)) = QF + 1
Dim i As Integer = 0
While QF > limites(i)
i += 1
End While
Return CLng(revenu * coeffR(i) - nbParts * coeffN(i))
End Function
End Class
یک شیء مالیات با دادههای مورد نیاز برای محاسبه مالیات یک مؤدی ایجاد میشود. این بخش ثابت شیء است. پس از ایجاد این شیء، میتوان متد **calculate** آن را بارها برای محاسبه مالیات مؤدی بر اساس وضعیت تأهل (متأهل یا مجرد)، تعداد فرزندان و حقوق سالانهاش فراخوانی کرد. یک برنامه آزمایشی ممکن است به این شکل باشد:
' گزینهها
Option Strict On
Option Explicit On
' فضاهای نام
Imports System
Imports Microsoft.VisualBasic
Module test
Sub Main()
' برنامه تعاملی محاسبه مالیات
'کاربر سه مورد داده را از طریق صفحهکلید وارد میکند: متأهل nbEnfants حقوق
' سپس برنامه مالیات قابل پرداخت را نمایش میدهد
Const syntaxe As String = "syntaxe : marié nbEnfants salaire" + ControlChars.Lf + "marié : o pour marié, n pour non marié" + ControlChars.Lf + "nbEnfants : nombre d'enfants" + ControlChars.Lf + "salaire : salaire annuel en F"
' جدولهای دادهای مورد نیاز برای محاسبه مالیات
Dim limites() As Decimal = {12620D, 13190D, 15640D, 24740D, 31810D, 39970D, 48360D, 55790D, 92970D, 127860D, 151250D, 172040D, 195000D, 0D}
Dim coeffR() As Decimal = {0D, 0.05D, 0.1D, 0.15D, 0.2D, 0.25D, 0.3D, 0.35D, 0.4D, 0.45D, 0.5D, 0.55D, 0.6D, 0.65D}
Dim coeffN() As Decimal = {0D, 631D, 1290.5D, 2072.5D, 3309.5D, 4900D, 6898.5D, 9316.5D, 12106D, 16754.5D, 23147.5D, 30710D, 39312D, 49062D}
' ایجاد یک شیء مالیاتی
Dim objImpôt As impot = Nothing
Try
objImpôt = New impot(limites, coeffR, coeffN)
Catch ex As Exception
Console.Error.WriteLine(("L'erreur suivante s'est produite : " + ex.Message))
Environment.Exit(1)
End Try
'حلقه بینهایت
Dim marié As String
Dim nbEnfants As Integer
Dim salaire As Long
While True
' پارامترهای محاسبه مالیات درخواست میشوند
Console.Out.Write("Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :")
Dim paramètres As String = Console.In.ReadLine().Trim()
' آیا اقدام خاصی لازم است؟
If paramètres Is Nothing OrElse paramètres = "" Then
Exit While
End If
'بررسی تعداد آرگومانها در خط واردشده
Dim erreur As Boolean = False
Dim args As String() = paramètres.Split(Nothing)
Dim nbParamètres As Integer = args.Length
If nbParamètres <> 3 Then
Console.Error.WriteLine(syntaxe)
erreur = True
End If
'بررسی اعتبار پارامترها
If Not erreur Then
' متأهل
marié = args(0).ToLower()
If marié <> "o" And marié <> "n" Then
erreur = True
End If
' nbEnfants
Try
nbEnfants = Integer.Parse(args(1))
If nbEnfants < 0 Then
Throw New Exception
End If
Catch
erreur = True
End Try
' حقوق
Try
salaire = Integer.Parse(args(2))
If salaire < 0 Then
Throw New Exception
End If
Catch
erreur = True
End Try
End If
' اگر پارامترها صحیح باشند – مالیات محاسبه میشود
If Not erreur Then
Console.Out.WriteLine(("impôt=" & objImpôt.calculer(marié = "o", nbEnfants, salaire) & " F"))
Else
Console.Error.WriteLine(syntaxe)
End If
End While
End Sub
End Module
در اینجا مثالی از اجرای برنامه قبلی آورده شده است:
dos>vbc /t:library impots.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
dir>dir
12/03/2004 18:24 4 096 impots.dll
12/03/2004 18:20 1 483 impots.vb
12/03/2004 18:21 2 805 test.vb
dos>vbc /r:impots.dll test.vb
Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 pour Microsoft (R) .NET Framework version 1.1.4322.573
dos>dir
12/03/2004 18:24 4 096 impots.dll
12/03/2004 18:20 1 483 impots.vb
12/03/2004 18:26 6 144 test.exe
12/03/2004 18:21 2 805 test.vb
dos>test
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :x x x
syntaxe : marié nbEnfants salaire
marié : o pour marié, n pour non marié
nbEnfants : nombre d'enfants
salaire : salaire annuel en F
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :o 2 200000
impôt=22504 F
Paramètres du calcul de l'impôt au format marié nbEnfants salaire ou rien pour arrêter :





