Skip to content

3. Sınıflar, yapılar, arayüzler

3.1. Örnek üzerinden nesne

3.1.1. Genel bilgiler

Şimdi örnek üzerinden nesne yönelimli programlamayı ele alacağız. Bir nesne, durumunu tanımlayan verileri (bunlara özellik denir) ve işlevleri (bunlara yöntem denir) içeren bir varlıktır. Bir nesne, sınıf adı verilen bir modele göre oluşturulur:

Public Class c1
     ' özellikler
    Private p1 As type1
    Private p2 As type2
....

     ' yöntem
    Public Sub m1(....)
...
    End Sub    

     ' yöntem
    Public Function m2(...)
....
    End Function    
End Class

Yukarıdaki C1 sınıfından yola çıkarak, çok sayıda O1, O2,… nesnesi oluşturulabilir. Hepsi p1, p2,… özelliklerine ve m3, m4,… yöntemlerine sahip olacaktır. Ancak pi özellikleri için farklı değerlere sahip olacaklardır ve böylece her biri kendine özgü bir duruma sahip olacaktır. Benzer şekilde, şu bildirim:

    dim i, j as integer

ifadesi, Integer türünde (sınıfında) iki nesne (burada bu terim yanlış kullanılmıştır) oluşturur. Bu nesnelerin tek özelliği, değerleridir. O1, C1 türünde bir nesne ise, O1.p1, O1'in p1 özelliğini, O1.m1 ise O1 sınıfının m1 yöntemini ifade eder. İlk nesne modelini ele alalım: personne sınıfı.

3.1.2. Kişi sınıfının tanımı

personne sınıfının tanımı şu şekilde olacaktır:


Public Class personne
    ' öznitelikler
    Private prenom As String
    Private nom As String
    Private age As Integer

    ' yöntem
    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

    ' yöntem
    Public Sub identifie()
        Console.Out.WriteLine((prenom & "," & nom & "," & age))
    End Sub
End Class

Burada bir sınıfın, yani bir veri türünün tanımını görüyoruz. Bu türden değişkenler oluşturduğumuzda, bunlara nesneler veya sınıf örnekleri adını vereceğiz. Dolayısıyla bir sınıf, nesnelerin oluşturulduğu bir kalıptır. Bir sınıfın üyeleri veya alanları veriler (öznitelikler), yöntemler (fonksiyonlar) veya özellikler olabilir. Özellikler, nesnenin özniteliklerinin değerini öğrenmek veya belirlemek için kullanılan özel yöntemlerdir. Bu alanlar, aşağıdaki üç anahtar kelimeden biriyle birlikte kullanılabilir:

privé
Özel (private) bir alana yalnızca sınıfın kendi iç yöntemleri erişebilir
public
Genel (public) bir alana, sınıf içinde tanımlanmış olsun ya da olmasın tüm işlevler tarafından erişilebilir
protégé
Korunan (protected) bir alana yalnızca sınıfın veya türetilmiş bir nesnenin (daha sonra miras kavramına bakınız) dahili yöntemleri tarafından erişilebilir.

Genel olarak, bir sınıfın verileri özel olarak bildirilirken, yöntemleri ve özellikleri genel olarak bildirilir. Bu, bir nesnenin kullanıcısının (programcı)

  • nesnenin özel verilerine doğrudan erişemez
  • nesnenin genel yöntemlerini ve özellikle de özel verilerine erişim sağlayan yöntemleri kullanabilir.

Bir sınıfın bildirim sözdizimi şöyledir:


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 ve public özniteliklerinin bildirilme sırası herhangi bir kural gerektirmez.

3.1.3. Yöntem,

Şu şekilde tanımlanan [personne] sınıfımıza geri dönelim:


Public Class personne
    ' özellikler
    Private prenom As String
    Private nom As String
    Private age As Integer

    ' yöntem
    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

    ' yöntem
    Public Sub identifie()
        Console.Out.WriteLine((prenom & "," & nom & "," & age))
    End Sub
End Class

initialise yönteminin rolü nedir? nom, prenom ve age, personne sınıfının özel verileri olduğundan, şu komutlar:

dim p1 as personne p1
p1.prenom="Jean"
p1.nom="Dupont"
p1.age=30

yazıları geçersizdir. personne türünde bir nesneyi genel bir yöntem aracılığıyla başlatmamız gerekir. Bu, initialise yönteminin görevidir. Şöyle yazacağız:

dim p1 as personne
p1.initialise("Jean","Dupont",30)

p1.initialise yazımı, initialise'in erişimi herkese açık olduğu için geçerlidir.

3.1.4. new operatörü

Komut dizisi

dim p1 as personne
p1.initialise("Jean","Dupont",30)

hatalıdır.

dim p1 as personne

komutu, p1'i personne türünde bir nesneye referans olarak tanımlamaktadır. Bu nesne henüz mevcut değildir ve bu nedenle p1 başlatılmamıştır. Bu, sanki şunu yazmış gibi bir durumdur:

dim p1 as personne=nothing

burada nothing anahtar sözcüğüyle, p1 değişkeninin henüz hiçbir nesneye referans vermediğini açıkça belirtmiş oluruz. Daha sonra şunu yazdığımızda

p1.initialise("Jean","Dupont",30)

yazdığımızda, p1 tarafından referans verilen nesnenin initialise yöntemini çağırmış oluruz. Ancak bu nesne henüz mevcut değildir ve derleyici bir hata bildirir. p1'in bir nesneye referans vermesi için şunu yazmak gerekir:

dim p1 as personne=new personne()

Bu, henüz başlatılmamış bir personne türü nesne oluşturur: nom ve prenom öznitelikleri, String türündeki nesnelere referanslar olduğundan nothing değerini alacak, ve age ise 0 değerini alacaktır. Dolayısıyla varsayılan bir başlatma söz konusudur. Artık p1 bir nesneye referans verdiğine göre, bu nesnenin başlatma komutu

p1.initialise("Jean","Dupont",30)

geçerlidir.

3.1.5. Me anahtar sözcüğü

initialise yönteminin koduna bakalım:


    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 komutu, geçerli nesnenin (Me) prenom özniteliğine P değerinin atandığını ifade eder. Me anahtar sözcüğü, geçerli nesneyi belirtir: yani, yürütülen yöntemin bulunduğu nesneyi. Bunu nasıl anlarız? Çağıran programda p1 tarafından referans verilen nesnenin nasıl başlatıldığını inceleyelim:

p1.initialise("Jean","Dupont",30)

p1 nesnesinin initialise yöntemi çağrılmaktadır. Bu yöntemde Me nesnesine atıfta bulunulduğunda, aslında p1 nesnesine atıfta bulunulmaktadır. initialise yöntemi şu şekilde de yazılabilirdi:


    Public Sub initialise(ByVal P As String, ByVal N As String, ByVal age As Integer)
        prenom = P
        nom = N
        Me.age = age
    End Sub    

Bir nesnenin yöntemi, bu nesnenin A özniteliğine başvurduğunda, Me.A yazımı örtük olarak kullanılır. Tanımlayıcı çakışması olduğunda ise bu yazım açıkça kullanılmalıdır. Aşağıdaki komutda durum böyledir:


Me.age=age;

burada age, hem geçerli nesnenin bir özniteliğini hem de yöntem tarafından alınan age parametresini ifade eder. Bu durumda, age özniteliğini Me.age olarak belirtmek suretiyle belirsizliği gidermek gerekir.

3.1.6. Bir test programı

İşte kısa bir test programı:


Public Class personne
    ' özellikler
    Private prenom As String
    Private nom As String
    Private age As Integer

    ' yöntem
    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

    ' yöntem
    Public Sub identifie()
        Console.Out.WriteLine((prenom & "," & nom & "," & age))
    End Sub
End Class

ve elde edilen sonuçlar:

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
dos>personne1
Jean,Dupont,30

3.1.7. Derlenmiş sınıf dosyası (assembly) kullanma

Önceki örnekte, test programımızda iki sınıf olduğu dikkatinizi çekecektir: personne ve test1 sınıfları. Bunu yapmanın başka bir yolu daha vardır:

  • "person" sınıfını, "assembly" adı verilen özel bir dosyaya derleriz. Bu dosyanın uzantısı .dll'dir

  • "person" sınıfını içeren derlemeyi referans alarak "test1" sınıfını derleriz.

İki kaynak dosyası şu şekilde olur:

test.vb

Module test1
    Sub Main()
        Dim p1 As New personne
        p1.initialise("Jean", "Dupont", 30)
        p1.identifie()
    End Sub
End module
personne2.vb

' seçenekler
Option Explicit On 
Option Strict On

' ad alanları
Imports System

Public Class personne
    ' özellikler
    Private prenom As String
    Private nom As String
    Private age As Integer

    ' yöntem
    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    'initialise

    ' yöntem
    Public Sub identifie()
        Console.Out.WriteLine((prenom & "," & nom & "," & age))
    End Sub    'identifie
End Class 'personne

personne sınıfı aşağıdaki komutla derlenir:

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

Derleme sonucunda personne2.dll dosyası oluşturuldu. "Assembly" dosyası oluşturulmasını belirten derleme seçeneği /t:library'tir. Şimdi test.vb dosyasını derleyelim:

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 derleme seçeneği, derleyiciye personne2.dll dosyasında belirli sınıfları bulacağını bildirir. test.vb kaynak dosyasında, test.vb kaynak dosyasında tanımlanmamış olan personne sınıfına bir referans bulduğunda, /r seçeneği tarafından referans verilen .dll dosyalarında personne sınıfını arayacaktır. Burada, personne2.dll derlemesinde personne sınıfını bulacaktır. Bu derlemeye başka sınıflar da eklenebilirdi. Derleme sırasında birden fazla derlenmiş sınıf dosyası kullanmak için şu şekilde yazılır:

vbc /r:fic1.dll /r:fic2.dll ... fichierSource.vb

test1.exe programının çalıştırılması şu sonuçları verir:

dos>test
Jean,Dupont,30

3.1.8. Başka bir yöntem başlatır

Yine personne sınıfını ele alalım ve ona aşağıdaki yöntemi ekleyelim:


    ' yöntem
    Public Sub initialise(ByVal P As personne)
        prenom = P.prenom
        nom = P.nom
        Me.age = P.age
    End Sub

Artık initialise adında iki yöntemimiz var: farklı parametreler kabul ettikleri sürece bu durum geçerlidir. Burada da durum böyledir. Parametre artık bir kişiye ait P referansıdır. P kişisinin öznitelikleri, bu durumda geçerli nesneye (Me) atanır. initialise yönteminin, P nesnesinin özniteliklerine doğrudan erişimi olduğu, ancak bu özniteliklerin private türünde olduğu dikkatinizi çekecektir. Bu her zaman geçerlidir: C sınıfına ait bir O1 nesnesi, her zaman aynı C sınıfına ait nesnelerin özniteliklerine erişebilir. İşte yeni personne sınıfının bir testi; bu sınıf, daha önce açıklandığı gibi personne.dll içinde derlenmiştir:


' seçenekler
Option Explicit On 
Option Strict On

' ad alanları
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

ve sonuçları:

p1=Jean,Dupont,30
p2=Jean,Dupont,30

3.1.9. Person sınıfının oluşturucuları

Oluşturucu, New adını taşıyan ve nesnenin oluşturulması sırasında çağrılan bir yordamdır. Genellikle nesneyi başlatmak için kullanılır. Bir sınıfın n argüman kabul eden bir oluşturucusu varsa argi, bu sınıfa ait bir nesnenin bildirilmesi ve başlatılması şu şekilde yapılabilir:


        dim objet as classe =new classe(arg1,arg2, ... argn)

veya


        dim objet as classe

        objet=new classe(arg1,arg2, ... argn)

Bir sınıfın bir veya daha fazla yapıcı işlevi varsa, bu sınıftan bir nesne oluşturmak için bu yapıcı işlevlerden birinin kullanılması zorunludur. C sınıfının hiçbir yapıcı işlevi yoksa, varsayılan olarak parametresiz yapıcı işlevi olan public New() kullanılır. Bu durumda nesnenin özellikleri varsayılan değerlerle başlatılır. Önceki programlarda da böyle olmuştu; orada şunu yazmıştık:

    dim p1 as personne
    p1=new personne

personne sınıfımıza iki yapıcı oluşturalım:


' seçenekler
Option Explicit On 
Option Strict On

' ad alanları
Imports System

' kişi sınıfı
Public Class personne
    ' özellikler
    Private prenom As String
    Private nom As String
    Private age As Integer

    ' oluşturucular
    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

    ' nesne başlatma yöntemleri
    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

    ' yöntem
    Public Sub identifie()
        Console.Out.WriteLine((prenom & "," & nom & "," & age))
    End Sub
End Class

Her iki yapıcı da sadece karşılık gelen initialise yöntemlerini çağırır. Hatırlatmak gerekirse, bir yapıcıda örneğin initialise(P) notasyonu bulunduğunda, derleyici bunu Me.initialise(P) olarak çevirir. Dolayısıyla, oluşturucuda initialise yöntemi, Me tarafından referans verilen nesne, yani o anda oluşturulmakta olan nesne üzerinde işlem yapmak üzere çağrılır. İşte kısa bir test programı:


' seçenekler 
Option Explicit On 
Option Strict On

' ad alanları
Imports System

' test sayfası
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

ve elde edilen sonuçlar:

p1=Jean,Dupont,30
p2=Jean,Dupont,30

3.1.10. Nesne referansları

Her zaman aynı personne sınıfını kullanıyoruz. Test programı şu şekilde olur:


' seçenekler
Option Explicit On 
Option Strict On

' ad alanları
Imports System

' test sayfası
Module test
    Sub Main()
        ' p1
        Dim p1 As New personne("Jean", "Dupont", 30)
        Console.Out.Write("p1=")
        p1.identifie()

        ' p2, p1 ile aynı nesneye başvurur
        Dim p2 As personne = p1
        Console.Out.Write("p2=")
        p2.identifie()

        ' p3, p1 tarafından referans verilen nesnenin bir kopyası olacak bir nesneye referans verir
        Dim p3 As New personne(p1)
        Console.Out.Write("p3=")
        p3.identifie()

        ' p1 tarafından referans verilen nesnenin durumu değiştirilir
        p1.initialise("Micheline", "Benoît", 67)
        Console.Out.Write("p1=")
        p1.identifie()

        ' p2=p1 olduğu için, p2'nin işaret ettiği nesnenin durumu değişmiş olmalıdır
        Console.Out.Write("p2=")
        p2.identifie()

        ' p3, p1 ile aynı nesneye referans vermediğinden, p3 tarafından referans verilen nesnenin durumu değişmemiş olmalıdır
        Console.Out.Write("p3=")
        p3.identifie()
    End Sub
End Module

Elde edilen sonuçlar şunlardır:

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 değişkeni şu şekilde tanımlandığında

dim p1 as personne=new personne("Jean","Dupont",30)

p1, personne("Jean","Dupont",30) nesnesine başvurur, ancak nesnenin kendisi değildir. C dilinde buna bir işaretçi denir; c.a.d, oluşturulan nesnenin adresidir. Ardından şunu yazarsak:

    p1=nothing

Değiştirilen personne("Jean","Dupont",30) nesnesi değil, değeri değişen p1 referansıdır. personne("Jean","Dupont",30) nesnesi, başka hiçbir değişken tarafından referanslanmıyorsa "kaybolur".

Şu kod yazıldığında:

dim p2 as personne=p1

yazıldığında, p2 işaretçisi başlatılır: bu işaretçi, p1 işaretçisiyle aynı nesneye "işaret eder" (aynı nesneyi gösterir). Dolayısıyla, p1 tarafından "işaret edilen" (veya referans verilen) nesne değiştirilirse, p2 tarafından referans verilen nesne de değiştirilmiş olur.

Şu kod yazıldığında:

dim p3 as personne =new personne(p1);

yazıldığında, p1 tarafından referans verilen nesnenin bir kopyası olan yeni bir nesne oluşturulur. Bu yeni nesne, p3 tarafından referans verilecektir. p1 tarafından "işaret edilen" (veya referans verilen) nesne değiştirilirse, p3 tarafından referans verilen nesne hiçbir şekilde değiştirilmez. Elde edilen sonuçlar da bunu göstermektedir.

3.1.11. Geçici nesneler

Bir ifadede, bir nesnenin oluşturucusuna açıkça başvurulabilir: nesne oluşturulur, ancak ona erişimimiz yoktur (örneğin, onu değiştirmek için). Bu geçici nesne, ifadenin değerlendirilmesi için oluşturulur ve ardından terk edilir. İşgal ettiği bellek alanı, daha sonra "çöp toplayıcı" adı verilen bir program tarafından otomatik olarak geri kazanılacaktır; bu programın görevi, program verileri tarafından artık referans gösterilmeyen nesnelerin işgal ettiği bellek alanını geri kazanmaktır. Aşağıdaki yeni test programını ele alalım:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

' test sayfası
Module test
    Sub Main()
        Dim p As New personne(New personne("Jean", "Dupont", 30))
        p.identifie()
    End Sub
End Module

ve personne sınıfının oluşturucularını bir mesaj görüntüleyecek şekilde değiştirelim:


    ' yapıcılar
    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

Şu sonuçları elde ediyoruz:

dos>test
Constructeur personne(String, String, integer)
Constructeur personne(personne)
Jean,Dupont,30

Bu, iki geçici nesnenin sırayla oluşturulduğunu göstermektedir.

3.1.12. Özel özniteliklerin okunması ve yazılması için yöntemler

personne sınıfına, nesnelerin özniteliklerinin durumunu okumak veya değiştirmek için gerekli yöntemleri ekliyoruz:


Imports System

Public Class personne

    ' özellikler
    Private prenom As [String]
    Private nom As [String]
    Private age As Integer

    ' oluşturucular
    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

    ' tanımlayıcılar
    Public Sub identifie()
        Console.Out.WriteLine((prenom + "," + nom + "," + age))
    End Sub

    ' erişim yöntemleri
    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

    'değiştiriciler
    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

Yeni sınıfı aşağıdaki programla test ediyoruz:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

' test sayfası
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

ve şu sonuçları elde ediyoruz:

P=(Jean,Michelin,34)
P=(Jean,Michelin,56)

3.1.13. Özellikler

Bir sınıfın özniteliklerine erişmenin başka bir yolu da özellikler oluşturmaktır. Bu özellikler, özel öznitelikleri sanki genelmiş gibi işlememize olanak tanır. Aşağıdaki personne sınıfını ele alalım; burada önceki erişim ve değiştirme yöntemleri, okuma ve yazma özellikleriyle değiştirilmiştir:


' seçenekler
Option Explicit On 
Option Strict On

' ad alanları
Imports System

' kişi sınıfı
Public Class personne

    ' özellikler
    Private _prenom As [String]
    Private _nom As [String]
    Private _age As Integer


    ' üreticiler
    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

    ' tanımlar
    Public Sub identifie()
        Console.Out.WriteLine((_prenom & "," & _nom & "," & _age))
    End Sub

    ' özellikler
    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)
            ' yaş geçerli mi?
            If Value >= 0 Then
                _age = Value
            Else
                Throw New Exception("âge (" & Value & ") invalide")
            End If
        End Set
    End Property
End Class

Bir Property özelliği, bir özniteliğin değerini okumaya (get) veya ayarlamaya (set) olanak tanır. Örneğimizde, özelliklerin temel özniteliklerin adlarını taşıması için öznitelik adlarının başına _ ön eki ekledik. Zira bir özellik, yönettiği özniteliğin adıyla aynı adı taşıyamaz; aksi takdirde sınıfta ad çakışması meydana gelir. Bu nedenle özniteliklerimize _prenom, _nom, _age adlarını verdik ve yapıcıları ile yöntemleri buna göre değiştirdik. Ardından nom, prenom ve age adlı üç özellik oluşturduk. Bir özellik şu şekilde tanımlanır:


    Public Property nom() As Type
        Get
...
        End Get
        Set(ByVal Value As Type)
...
        End Set    
    End Property

burada Type, özellik tarafından yönetilen özniteliğin türü olmalıdır. Bu özellik, get ve set adlı iki yönteme sahip olabilir. Get yöntemi genellikle yönettiği özniteliğin değerini döndürmekle görevlidir (başka bir şey de döndürebilir, bunu engelleyen bir şey yoktur). set yöntemi, value adlı bir parametre alır ve bunu normalde yönettiği özniteliğe atar. Bu yöntem, alınan değerin geçerliliğini kontrol etmek için bu fırsatı değerlendirebilir ve değer geçersiz çıkarsa bir istisna oluşturabilir. Burada yaş için yapılan da budur.

Bu get ve set yöntemleri nasıl çağrılır? Aşağıdaki test programını ele alalım:


' seçenekler
Option Explicit On 
Option Strict On

' ad alanları
Imports System

' test sayfası
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

Şu komutta

        Console.Out.WriteLine(("P=(" & P.prenom & "," & P.nom & "," & P.age & ")"))

komutunda, P kişisinin prenom, nom ve age özelliklerinin değerleri alınmaya çalışılır. Bu durumda, bu özelliklerin get yöntemi çağrılır ve bu yöntem, yönettikleri özniteliğin değerini döndürür.

Aşağıdaki komutta

        P.age = 56

komutunda, age özelliğinin değeri ayarlanmak istenmektedir. Bu durumda, bu özelliğin set yöntemi çağrılır. Bu yöntem, value parametresinde 56 değerini alır.

C sınıfına ait ve yalnızca get yöntemini tanımlayan bir P özelliği, salt okunur olarak adlandırılır. c, C sınıfına ait bir nesne ise, c.P=değer işlemi derleyici tarafından reddedilir.

Önceki test programının çalıştırılması şu sonuçları verir:

P=(Jean,Michelin,34)
P=(Jean,Michelin,56)
âge (-4) invalide

Dolayısıyla özellikler, özel öznitelikleri sanki genelmiş gibi işlememize olanak tanır.

3.1.14. Sınıf yöntemleri ve öznitelikleri

Bir uygulamada oluşturulan [personne] nesnelerinin sayısını saymak istediğimizi varsayalım. Bir sayacı kendimiz yönetebiliriz, ancak burada veya orada oluşturulan geçici nesneleri unutma riski vardır. [personne] sınıfının oluşturucularına, bir sayacı artıran bir komut eklemek daha güvenli görünür. Sorun, oluşturucunun sayacı artırabilmesi için bu sayaca bir referans aktarılmasıdır: onlara yeni bir parametre aktarılması gerekir. Sayacı sınıf tanımına da dahil edebiliriz. Bu, sınıfın kendisinin bir özniteliği olduğu ve bu sınıfa ait belirli bir nesnenin özniteliği olmadığı için, Shared anahtar sözcüğüyle farklı şekilde tanımlanır:

    Private Shared _nbPersonnes As Long = 0

Buna başvurmak için, personne._nbPersonnes yazarak bunun personne sınıfının kendisinin bir özniteliği olduğunu gösteririz. Burada, sınıfın dışından doğrudan erişilemeyen özel bir öznitelik oluşturduk. Bu nedenle, nbPersonnes sınıf özniteliğine erişim sağlamak için bir genel özellik oluşturuyoruz. nbPersonnes değerini almak için, bu özelliğin get yönteminin belirli bir personne nesnesine ihtiyacı yoktur: çünkü _nbPersonnes belirli bir nesnenin özniteliği değil, tüm sınıfın özniteliğidir. Bu nedenle, yine Shared olarak tanımlanmış bir özelliğe ihtiyaç vardır:

    Public Shared ReadOnly Property nbPersonnes() As Long
        Get
            Return _nbPersonnes
        End Get
    End Property

Bu, dışarıdan personne.nbPersonnes sözdizimiyle çağrılacaktır. Özellik, set yöntemi sunmadığı için salt okunur olarak tanımlanmıştır (ReadOnly). İşte bir örnek. personne sınıfı şu şekilde olur:


Option Explicit On 
Option Strict On

' ad alanları
Imports System

' sınıf
Public Class personne
    ' sınıf öznitelikleri
    Private Shared _nbPersonnes As Long = 0

    ' örnek öznitelikleri
    Private _prenom As [String]
    Private _nom As [String]
    Private _age As Integer

    ' yapıcılar
    Public Sub New(ByVal P As [String], ByVal N As [String], ByVal age As Integer)
        ' bir kişi daha
        _nbPersonnes += 1
        Me._prenom = P
        Me._nom = N
        Me._age = age
    End Sub

    Public Sub New(ByVal P As personne)
        ' bir kişi daha
        _nbPersonnes += 1
        Me._prenom = P._prenom
        Me._nom = P._nom
        Me._age = P._age
    End Sub

    ' tanımlar
    Public Sub identifie()
        Console.Out.WriteLine((_prenom & "," & _nom & "," & _age))
    End Sub

    ' sınıf özelliği
    Public Shared ReadOnly Property nbPersonnes() As Long
        Get
            Return _nbPersonnes
        End Get
    End Property

    ' örnek özellikleri
    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)
            ' yaş geçerli mi?
            If Value >= 0 Then
                _age = Value
            Else
                Throw New Exception("âge (" & Value & ") invalide")
            End If
        End Set
    End Property
End Class

Aşağıdaki programla:


' seçenekler
Option Explicit On 
Option Strict On

' ad alanları
Imports System

' test pg'si
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

şu sonuçlar elde edilir:

    Nombre de personnes créées : 2

3.1.15. Bir nesnenin bir fonksiyona aktarılması

Daha önce de belirttiğimiz gibi, varsayılan olarak VB.NET, bir fonksiyonun etkin parametrelerini değer olarak aktarır: etkin parametrelerin değerleri, biçimsel parametrelere kopyalanır. Bir nesne söz konusu olduğunda, nesne referansı yerine sistematik olarak nesne denilmesinden kaynaklanan dil kullanımındaki yanlışlığa aldanmamak gerekir. Bir nesne, yalnızca o nesneye ait bir referans (işaretçi) aracılığıyla işlenir. Dolayısıyla bir fonksiyona aktarılan, nesnenin kendisi değil, o nesneye ait bir referanstır. Bu nedenle, biçimsel parametreye kopyalanan nesnenin kendisinin değeri değil, referansın değeridir: yeni bir nesne oluşturulmaz. R1 nesne referansı bir fonksiyona aktarılırsa, bu referans karşılık gelen biçimsel parametreye (R2) kopyalanır. Dolayısıyla, R2 ve R1 referansları aynı nesneyi işaret eder. İşlev, R2 tarafından işaret edilen nesneyi değiştirirse, R1 tarafından referans verilen nesneyi de değiştirir; çünkü ikisi aynıdır.

Aşağıdaki örnek bunu göstermektedir:


' seçenekler
Option Explicit On 
Option Strict On

' ad alanları
Imports System

' test sayfası
Module test
    Sub Main()
        ' bir kişi p1
        Dim p1 As New personne("Jean", "Dupont", 30)

        ' görüntüleme p1
        Console.Out.Write("Paramètre effectif avant modification : ")
        p1.identifie()

        ' p1'in düzenlenmesi
        modifie(p1)

        ' p1 görüntüleme
        Console.Out.Write("Paramètre effectif après modification : ")
        p1.identifie()
    End Sub

    Sub modifie(ByVal P As personne)
        ' kişi P görüntüleme
        Console.Out.Write("Paramètre formel avant modification : ")
        P.identifie()
        ' P düzenleme
        P.prenom = "Sylvie"
        P.nom = "Vartan"
        P.age = 52
        ' P görüntüleme
        Console.Out.Write("Paramètre formel après modification : ")
        P.identifie()
    End Sub
End Module

Elde edilen sonuçlar şunlardır:

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

Görüldüğü üzere, yalnızca bir nesne oluşturulmuştur: Main prosedürüne ait p1 nesnesi; ve bu nesne, modifie işlevi tarafından değiştirilmiştir.

3.1.16. Kişi tablosu

Bir nesne, diğer veriler gibi bir veridir ve bu nedenle birden fazla nesne bir dizide bir araya getirilebilir:


' seçenekler
Option Explicit On 
Option Strict On

' ad alanları
Imports System

' test sayfası
Module test
    Sub Main()
        ' kişi tablosu
        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)
        ' görüntüleme
        Console.Out.WriteLine("----------------")
        Dim i As Integer
        For i = 0 To amis.Length - 1
            amis(i).identifie()
        Next i
    End Sub
End Module

Dim amis(2) As personne komutu, personne türünde 3 elemanlı bir dizi oluşturur. Bu 3 eleman burada nothing ve c.a.d değerleriyle başlatılır; bu değerler herhangi bir nesneye referans vermez. Yine, dilin yanlış kullanımı nedeniyle, nesne dizisinden söz ediliyor; oysa bu sadece nesne referanslarından oluşan bir dizidir. Kendisi de bir nesne olan nesne dizisinin oluşturulması, elemanlarının türünde hiçbir nesne oluşturmaz: bunu daha sonra yapmak gerekir. Aşağıdaki sonuçlar elde edilir:

Jean,Dupont,30
Sylvie,Vartan,52
Neil,Armstrong,66

3.2. Örnekle Kalıtım

3.2.1. Genel Bilgiler

Burada miras kavramını ele alıyoruz. Mirasın amacı, mevcut bir sınıfı ihtiyaçlarımıza uygun hale getirmek için "kişiselleştirmektir". enseignant sınıfını oluşturmak istediğimizi varsayalım: bir öğretmen, özel bir kişidir. Başka bir kişinin sahip olmayacağı özellikleri vardır: örneğin, öğrettiği ders. Ancak aynı zamanda her insanın sahip olduğu özelliklere de sahiptir: adı, soyadı ve yaşı. Dolayısıyla bir öğretmen, personne sınıfının tam bir parçasıdır, ancak ek özelliklere de sahiptir. enseignant sınıfını sıfırdan yazmak yerine, personne sınıfının mevcut özelliklerini alıp bunları öğretmenlerin kendine özgü özelliklerine uyarlamayı tercih ederiz. Bunu mümkün kılan şey, miras alma kavramıdır. enseignant sınıfının personne sınıfının özelliklerini miras aldığını ifade etmek için şunu yazacağız:


Public Class enseignant
    Inherits personne

İki satırlık bu özel sözdizimine dikkat edilmelidir. personne sınıfına üst sınıf (veya ana sınıf), enseignant sınıfına ise türetilmiş sınıf (veya alt sınıf) denir. Bir enseignant nesnesi, bir personne nesnesinin tüm özelliklerine sahiptir: aynı özniteliklere ve yöntemlere sahiptir. Ana sınıfın bu öznitelikleri ve yöntemleri, alt sınıfın tanımında tekrarlanmaz; sadece alt sınıf tarafından eklenen öznitelikler ve yöntemler belirtilir. personne sınıfının şu şekilde tanımlandığını varsayalım:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

' kişi sınıfı
Public Class personne

    ' sınıf öznitelikleri
    Private Shared _nbPersonnes As Long = 0

    ' örnek öznitelikleri
    Private _prenom As [String]
    Private _nom As [String]
    Private _age As Integer


    ' oluşturucular
    Public Sub New(ByVal P As [String], ByVal N As [String], ByVal age As Integer)
        ' bir kişi daha
        _nbPersonnes += 1
        ' oluşturma
        Me._prenom = P
        Me._nom = N
        Me._age = age
        ' izleme
        Console.Out.WriteLine("Construction personne(string, string, int)")
    End Sub


    Public Sub New(ByVal P As personne)
        ' bir kişi daha
        _nbPersonnes += 1
        ' inşaat
        Me._prenom = P._prenom
        Me._nom = P._nom
        Me._age = P._age
        ' takip
        Console.Out.WriteLine("Construction personne(string, string, int)")
    End Sub

    ' sınıf özelliği
    Public Shared ReadOnly Property nbPersonnes() As Long
        Get
            Return _nbPersonnes
        End Get
    End Property

    ' örnek özellikleri
    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)
            ' yaş geçerli mi?
            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 yöntemi, kişiyi tanımlayan ve salt okunur olan identité özelliği ile değiştirilmiştir. personne sınıfından miras alan bir enseignant sınıfı oluşturuyoruz:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

Public Class enseignant
    Inherits personne
    ' özellikler
    Private _section As Integer

    ' oluşturucu
    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
        ' izleme
        Console.Out.WriteLine("Construction enseignant(string,string,int,int)")
    End Sub

    ' bölüm özelliği
    Public Property section() As Integer
        Get
            Return _section
        End Get
        Set(ByVal Value As Integer)
            _section = Value
        End Set
    End Property
End Class 

enseignant sınıfı, personne sınıfının yöntemlerine ve özniteliklerine şunları ekler:

  • section özniteliği; bu, öğretmenin öğretmen kadrosu içinde ait olduğu bölüm numarasıdır (genel olarak her ders dalı için bir bölüm)
  • bir öğretmenin tüm özniteliklerini sıfırlamaya olanak tanıyan yeni bir oluşturucu

Bildirim


Public Class enseignant
    Inherits personne

, enseignant sınıfının personne sınıfından türediğini belirtir.

3.2.2. Öğretmen nesnesinin oluşturulması

enseignant sınıfının oluşturucusu şöyledir:


    ' oluşturucu
    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
         ' takip
        Console.Out.WriteLine("Construction enseignant(string,string,int,int)")
    End Sub    

Beyanname


    Public Sub New(ByVal P As String, ByVal N As String, ByVal age As Integer, ByVal section As Integer)

, yapıcının dört parametre aldığını belirtir: P, N, age, section. Bu yapıcı, üç parametreyi ((P,N,age)) temel sınıfına, yani buradaki personne sınıfına aktarmalıdır. Bu sınıfın, aktarılan parametrelerle ((P,N,age)) bir kişi nesnesi oluşturmaya olanak tanıyan personne(string, string, int) adlı bir yapıcıya sahip olduğu bilinmektedir. [enseignant] sınıfı, (P, N, yaş) parametrelerini temel sınıfına şu şekilde aktarır:


        MyBase.New(P, N, age)

Temel sınıfın oluşturulması tamamlandıktan sonra, enseignant nesnesinin oluşturulması, oluşturucunun gövdesinin yürütülmesiyle devam eder:


        Me._section = section

Özetle, türetilmiş bir sınıfın oluşturucusu:

  • oluşturulması için gerekli parametreleri temel sınıfa aktarır
  • diğer parametreleri, kendisine özgü öznitelikleri başlatmak için kullanır

Şu şekilde yazmak da tercih edilebilirdi:


    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
        ' takip
        Console.Out.WriteLine("Construction enseignant(string,string,int,int)")
    End Sub    

Bu imkansız. personne sınıfı, _prenom, _nom ve _age adlı üç alanını özel (private) olarak tanımlamıştır. Yalnızca aynı sınıfa ait nesneler bu alanlara doğrudan erişebilir. Buradaki gibi alt nesneler de dahil olmak üzere diğer tüm nesneler, bu alanlara erişmek için genel yöntemleri kullanmak zorundadır. personne sınıfı bu üç alanı korumalı (protected) olarak tanımlamış olsaydı durum farklı olurdu: bu durumda, türetilmiş sınıfların bu üç alana doğrudan erişmesine izin vermiş olurdu. Örneğimizde, üst sınıfın oluşturucusunu kullanmak doğru çözümdü ve bu genel olarak uygulanan yöntemdir: bir alt sınıf nesnesi oluşturulurken, önce üst sınıf nesnesinin oluşturucusu çağrılır, ardından bu sefer alt sınıf nesnesine (örneğimizde section) özgü başlatma işlemleri tamamlanır.

personne ve enseignant sınıflarını derlemelere derleyelim:

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 alt sınıfını derlemek için, personne sınıfını içeren personne.dll dosyasına referans verilmesi gerektiği dikkatinizi çekecektir. İlk test programımızı deneyelim:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

Module test
    Sub Main()
        Console.Out.WriteLine(New enseignant("Jean", "Dupont", 30, 27).identite)
    End Sub
End Module

Bu program, yalnızca bir enseignant nesnesi (new) oluşturup onu tanımlamakla yetinir. enseignant sınıfında identité adlı bir yöntem bulunmamaktadır, ancak üst sınıfında bu yöntem mevcuttur ve üstelik genel erişimlidir: miras yoluyla bu yöntem, enseignant sınıfının genel erişimli bir yöntemi haline gelir. Elde edilen sonuçlar şunlardır:

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)

Görüldüğü gibi:

  • personne nesnesi, enseignant nesnesinden önce oluşturulmuştur
  • elde edilen kimlik, personne nesnesine aittir

3.2.3. Bir yöntem veya özelliğin aşırı yüklenmesi

Önceki örnekte, öğretmenin personne kısmının kimliğini elde ettik, ancak enseignant sınıfına (bölüm) özgü bazı bilgiler eksik. Bu nedenle, öğretmeni tanımlamaya yarayan bir özellik yazmamız gerekiyor:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

Public Class enseignant
    Inherits personne
    ' özellikler
    Private _section As Integer

    ' oluşturucu
    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
        ' izleme
        Console.Out.WriteLine("Construction enseignant(string,string,int,int)")
    End Sub

    ' bölüm özelliği
    Public Property section() As Integer
        Get
            Return _section
        End Get
        Set(ByVal Value As Integer)
            _section = Value
        End Set
    End Property

    ' kimlik özelliğinin yeniden tanımlanması
    Public Shadows ReadOnly Property identite() As String
        Get
            Return "enseignant(" & MyBase.identite & "," & _section & ")"
        End Get
    End Property
End Class

enseignant sınıfının identite yöntemi, ana sınıfının (MyBase.identite) identite yöntemini kullanır "personne" kısmını görüntülemek için kullanır ve ardından enseignant sınıfına özgü olan _section alanıyla tamamlar. identite özelliğinin tanımına dikkat edelim:


    Public Shadows ReadOnly Property identite() As String

Bu, identite özelliğinin, üst sınıfta bulunabilecek aynı isimli yöntemi "gizlediğini" gösterir. enseignant E nesnesini ele alalım. Bu nesne, kendi içinde bir personne nesnesi içerir:

"identite" özelliği hem enseignant sınıfında hem de üst sınıfı olan personne sınıfında tanımlanmıştır. Alt sınıf olan enseignant'te, identite özelliğinin önüne, enseignant. sınıfı için yeni bir identite özelliğinin yeniden tanımlandığını belirtmek üzere shadows anahtar sözcüğü eklenmelidir


    Public Shadows ReadOnly Property identite() As String

enseignant sınıfı artık iki identite özelliğine sahiptir:

  • ana sınıftan miras alınan özellik personne
  • kendine ait olan

E, bir enseignant nesnesi ise, E.identite, enseignant sınıfının identite yöntemini belirtir. Ana sınıfın identite özelliğinin, alt sınıfın identite özelliği tarafından "yeniden tanımlandığı" söylenir. Genel olarak, O bir nesne ve M bir yöntem ise, O.M yöntemini çalıştırmak için sistem, M yöntemini aşağıdaki sırayla arar:

  • O nesnesinin sınıfında
  • varsa, üst sınıfında
  • varsa, ana sınıfının ana sınıfında
  • vb…

Dolayısıyla miras, alt sınıfta üst sınıftaki aynı isimli yöntemleri/özellikleri yeniden tanımlamaya olanak tanır. Bu, alt sınıfın kendi ihtiyaçlarına göre uyarlanmasını sağlar. Biraz sonra ele alacağımız polimorfizmle birleştiğinde, yöntemlerin/özelliklerin aşırı yüklenmesi, mirasın en önemli avantajıdır. Önceki örnekle devam edelim:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

Module test
    Sub Main()
        Console.Out.WriteLine(New enseignant("Jean", "Dupont", 30, 27).identite)
    End Sub
End Module

Bu sefer elde edilen sonuçlar şunlardır:

Construction personne(string, string, int)
Construction enseignant(string,string,int,int)
enseignant(personne(Jean,Dupont,30),27)

3.2.4. Polimorfizm

Şu sınıf dizisini ele alalım: C0 C1 C2 … Burada Ci Cj, Cj sınıfının Ci sınıfından türetildiğini gösterir. Bu, Cj sınıfının Ci sınıfının tüm özelliklerine ek olarak başka özelliklere de sahip olduğu anlamına gelir. Ci türündeki Oi nesneleri olsun. Şu şekilde yazmak geçerlidir:

    Oi=Oj avec j>i

Nitekim, miras yoluyla Cj sınıfı, Ci sınıfının tüm özelliklerine ek olarak başka özelliklere de sahiptir. Dolayısıyla, Cj türündeki bir Oj nesnesi, kendi içinde Ci türünde bir nesne barındırır. Şu işlem:

Oi=Oj

işlemi, Oi'nin Oj nesnesinde bulunan Ci türündeki nesneye bir referans olmasını sağlar.

Ci sınıfına ait bir Oi değişkeninin, aslında sadece Ci sınıfına ait bir nesneye değil, aynı zamanda Ci sınıfından türetilmiş herhangi bir nesneye de başvurabilmesi durumuna polimorfizm denir: bir değişkenin farklı nesne türlerine başvurabilme özelliği. Bir örnek verelim ve herhangi bir sınıftan bağımsız olan aşağıdaki fonksiyonu ele alalım:


    Sub affiche(ByVal p As personne)

Aşağıdaki şekilde de yazabiliriz:

    dim p as personne
    ...
    affiche(p);

ya da

    dim e as enseignant
    ...
    affiche(e);

Bu son durumda, affiche işlevinin personne türündeki biçimsel parametresi, enseignant türünde bir değer alacaktır. enseignant türü, personne türünden türediği için bu işlem geçerlidir.

3.2.5. Yeniden tanımlama ve polimorfizm

affiche prosedürümüzü tamamlayalım:


    Sub affiche(ByVal p As personne)
         ' p kimliğini göster
        Console.Out.WriteLine(p.identite)
    End Sub    

p.identite yöntemi, personne. nesnesini tanımlayan bir karakter dizisi döndürür. Önceki örneğimizde, enseignant nesnesi söz konusu olduğunda ne olur:


        Dim e As New enseignant("Lucile", "Dumas", 56, 61)
        affiche(e)

Şu örneği inceleyelim:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

Module test
    Sub Main()
        ' bir öğretmen
        Dim e As New enseignant("Lucile", "Dumas", 56, 61)
        affiche(e)
        ' bir kişi
        Dim p As New personne("Jean", "Dupont", 30)
        affiche(p)
    End Sub

    ' görüntüler
    Sub affiche(ByVal p As personne)
        ' p kimliğini gösterir
        Console.Out.WriteLine(p.identite)
    End Sub
End Module

Elde edilen sonuçlar şunlardır:

Construction personne(string, string, int)
Construction enseignant(string,string,int,int)
personne(Lucile,Dumas,56)
Construction personne(string, string, int)
personne(Jean,Dupont,30)

Çalıştırma sonucu, p.identite komutunun her seferinde bir personne nesnesinin identite özelliğini çalıştırdığını, enseignant'te bulunan e kişisini ve ardından personne'in kendisini çalıştırdığı görülmektedir. Bu işlem, affiche'e parametre olarak gerçekten geçirilen nesneye uymamıştır. enseignant e nesnesinin tam kimliğini elde etmeyi tercih ederdik. Bunun için p.identite notasyonunun, p tarafından gerçekte işaret edilen nesnenin identite özelliğine atıfta bulunması gerekirdi; "personne" nesnesinin identite özelliğine değil, p tarafından gerçekten işaret edilen nesnenin identite özelliğine atıfta bulunması gerekirdi. Bu sonuca, identite'i temel sınıf personne içinde yeniden tanımlanabilir (overridable) bir özellik olarak bildirerek ulaşılabilir:


    Public Overridable ReadOnly Property identite() As String
        Get
            Return "personne(" & _prenom & "," & _nom & "," & age & ")"
        End Get
    End Property

overridable anahtar sözcüğü, identite'i yeniden tanımlanabilir veya sanal bir özellik haline getirir. Bu anahtar sözcük, yöntemlere de uygulanabilir. Sanal bir özelliği veya yöntemi yeniden tanımlayan alt sınıflar, yeniden tanımladıkları özellik/yöntemi nitelemek için shadows yerine overrides anahtar sözcüğünü kullanmalıdır. Dolayısıyla, enseignant sınıfında, identite özelliği şu şekilde tanımlanmıştır:


    ' kimlik özelliğinin üst yazılması
    Public Overrides ReadOnly Property identite() As String
        Get
            Return "enseignant(" & MyBase.identite & "," & _section & ")"
        End Get
    End Property

Test programı:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

Module test
    Sub Main()
        ' bir öğretmen
        Dim e As New enseignant("Lucile", "Dumas", 56, 61)
        affiche(e)
        ' bir kişi
        Dim p As New personne("Jean", "Dupont", 30)
        affiche(p)
    End Sub

    ' görüntüler
    Sub affiche(ByVal p As personne)
        ' kimlik bilgilerini göster
        Console.Out.WriteLine(p.identite)
    End Sub
End Module

şu sonuçları verir:

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)

Bu sefer öğretmenin tam kimliğini elde ettik. Şimdi bir özellik yerine bir yöntem tanımlayalım. object sınıfı, tüm VB.NET sınıflarının "ana" sınıfıdır. Dolayısıyla şunu yazdığımızda:

    public class personne

yazdığımızda, dolaylı olarak şunu yazmış oluruz:

    public class personne 
         inherits object

object sınıfı, ToString adlı bir sanal yöntem tanımlar:

Image

ToString yöntemi, aşağıdaki örnekte gösterildiği gibi nesnenin ait olduğu sınıfın adını döndürür:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

Module test2
    Sub Main()
        ' bir öğretmen
        Console.Out.WriteLine(New enseignant("Lucile", "Dumas", 56, 61).ToString())
        ' bir kişi
        Console.Out.WriteLine(New personne("Jean", "Dupont", 30).ToString())
    End Sub
End Module

Elde edilen sonuçlar şunlardır:

Construction personne(string, string, int)
Construction enseignant(string,string,int,int)
enseignant
Construction personne(string, string, int)
personne

personne ve enseignant sınıflarında ToString yöntemini yeniden tanımlamamış olsak da, object sınıfındaki ToString yönteminin yine de nesnenin gerçek sınıf adını görüntüleyebildiğini görebiliriz. personne ve enseignant sınıflarındaki ToString yöntemini yeniden tanımlayalım:


    ' ToString
    Public Overrides Function ToString() As String
        ' özdeşlik özelliğini tanırız
        Return identite
    End Function

Tanım her iki sınıfta da aynıdır. Aşağıdaki test programını ele alalım:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

Module test
    Sub Main()
        ' bir öğretmen
        Dim e As New enseignant("Lucile", "Dumas", 56, 61)
        affiche(e)
        ' bir kişi
        Dim p As New personne("Jean", "Dupont", 30)
        affiche(p)
    End Sub

    ' afiş
    Sub affiche(ByVal p As personne)
        ' kimlik bilgilerini göster
        Console.Out.WriteLine(p.identite)
    End Sub
End Module

Çalıştırma sonuçları şöyledir:

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. Bir sınıf için bir indeksleyici tanımlama

.NET platformunda önceden tanımlanmış olan [ArrayList] sınıfını ele alalım. Bu sınıf, nesneleri bir listede saklamaya olanak tanır. Sınıf, [System.Collections] ad alanına aittir. Aşağıdaki örnekte, bu sınıfı (genel anlamıyla) bir kişi listesini saklamak için kullanıyoruz:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System
Imports System.Collections

' sınıf listeDePersonnes
Public Class listeDePersonnes
    Inherits ArrayList

    ' listeye kişi eklemek için
    Public Overloads Sub Add(ByVal p As personne)
        MyBase.Add(p)
    End Sub

    ' bir indeksleyici
    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

    ' başka bir indeksleyici
    Default Public Shadows ReadOnly Property Item(ByVal N As String) As Integer
        Get
            ' N adlı kişiyi arıyoruz
            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
        ' (el1, el2, ..., eln) değerlerini döndürür
        Dim liste As String = "("
        Dim i As Integer
        ' dinamik diziyi tarıyoruz
        For i = 0 To (Count - 2)
            liste += "[" + Me(i).ToString + "]" + ","
        Next i        'for
        ' son eleman
        If Count <> 0 Then
            liste += "[" + Me(i).ToString + "]"
        End If
        liste += ")"
        Return liste
    End Function
End Class

[ArrayList] sınıfının bazı özellikleri ve yöntemleri hakkında birkaç bilgi verelim:

Count
Listenin eleman sayısını veren özellik
Add(Object)
listeye bir nesne eklemeye yarayan yöntem
Item(Integer i)
listenin i numaralı öğesini veren yöntem

Listedeki i numaralı öğeyi elde etmek için [liste.Item(i)] yazmadığımızı, bunun yerine doğrudan [liste(i)] yazdığımızı fark ediyoruz; bu ilk bakışta hatalı gibi görünüyor. Bununla birlikte bu mümkündür, çünkü [ArrayList] sınıfı, aşağıdaki sözdizimine benzer şekilde [Item] adlı bir varsayılan özellik tanımlamaktadır:


    Default Public Property Item(ByVal i As Integer) As Object
        Get
...
        End Get
        Set(ByVal Value As personne)
...
        End Set    
    End Property

Derleyici, [liste(i)] notasyonuyla karşılaştığında, [ArrayList] sınıfının aşağıdaki imzaya sahip bir özellik tanımlayıp tanımlamadığını arar:


    Default Public Property Proc(ByVal var As Integer) As Type

Burada, [Item] yordamını bulacaktır. Ardından, [liste(i)] yazımını [liste.Item(i)] olarak çevirecektir. [Item] özelliğine, [ArrayList] sınıfının varsayılan indeksli özelliği denir. Yukarıdaki programın çalıştırılması aşağıdaki sonuçları verir:

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] adlı bir sınıf oluşturalım; bu sınıf, bir kişi listesi olacak, yani [ArrayList] sınıfından türetilmesi doğal görünen özel bir liste olacaktır:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System
Imports System.Collections

' sınıf listeDePersonnes
Public Class listeDePersonnes
    Inherits ArrayList

    ' listeye bir kişi eklemek için
    Public Shadows Sub Add(ByVal p As Object)
        ' p'nin bir kişi olması gerekir
        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

    ' bir indeksleyici
    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
        ' (el1, el2, ..., eln) değerini döndürür
        Dim liste As String = "("
        Dim i As Integer
        ' dinamik diziyi tarar
        For i = 0 To (Count - 2)
            liste += "[" + Me(i).ToString + "]" + ","
        Next i        'for
        ' son eleman
        If Count <> 0 Then
            liste += "[" + Me(i).ToString + "]"
        End If
        liste += ")"
        Return liste
    End Function
End Class

Sınıf, aşağıdaki yöntemleri ve özellikleri içerir:

ToString
listenin içeriğini "temsil eden" bir karakter dizesi döndürür
Add(personne)
Listeye bir kişi eklemeye yarayan yöntem
Item(Integer i)
listeye i numaralı kişiyi veren varsayılan indeksli özellik

Yeni noktaları ele alalım:

Yeni bir yöntem olan [Add] oluşturulmuştur.


     ' listeye bir kişi eklemek için
    Public Shadows Sub Add(ByVal p As Object)
        ' p'nin bir kişi olması gerekir
        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

Aynı imzaya sahip, üst sınıf [ArrayList]'te zaten bir tane mevcut olduğundan, yeni yordamın üst sınıftakini değiştirdiğini belirtmek için [Shadows] anahtar sözcüğü kullanılmıştır. Alt sınıftaki [Add] yöntemi, eklenen nesnenin gerçekten [personne] türünde olup olmadığını veya [TypeOf] işleviyle türetilmiş olup olmadığını kontrol eder. Aksi takdirde, [Throw] komutuyla bir istisna atılır. Eklenen nesne gerçekten [personne] türündeyse, ekleme işlemi için temel sınıfın [Add] yöntemi kullanılır.

Bir indeksli özellik oluşturulur:


    ' bir indeksleyici
    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

Temel sınıfta aynı imzaya sahip [Item] adlı bir varsayılan özellik zaten mevcuttur. Bu nedenle, yeni indeksli özellik [Index]'in temel sınıftaki [Item] özelliğini "gizleyeceğini" belirtmek için [Shadows] anahtar sözcüğünü kullanmak zorundayız. Her iki özelliğin adı aynı olmasa bile bu durumun geçerli olduğu unutulmamalıdır. [Index] özelliği, listedeki i numaralı kişiye referans verilmesini sağlar. Bu özellik, altta yatan [ArrayList] nesnesinin i numaralı öğesine erişmek için temel sınıfın [Item] özelliğine dayanır. [Item] özelliğinin [Object] türündeki öğelerle çalışırken, [Index] özelliğinin ise [personne] türündeki öğelerle çalıştığı dikkate alınarak tür değişiklikleri yapılmıştır.

Son olarak, [ArrayList] sınıfının [ToString] yöntemini yeniden tanımlıyoruz (Overrides):


    ' toString
    Public Overrides Function ToString() As String
        ' (el1, el2, ..., eln) değerini döndürür
        Dim liste As String = "("
        Dim i As Integer
        ' dinamik diziyi tarar
        For i = 0 To (Count - 2)
            liste += "[" + Me(i).ToString + "]" + ","
        Next i        'for
         ' son eleman
        If Count <> 0 Then
            liste += "[" + Me(i).ToString + "]"
        End If
        liste += ")"
        Return liste
    End Function

Bu yöntem, "(e1,e2,...,en)" biçiminde bir karakter dizesi döndürür; burada ei, listenin elemanlarıdır. [Me(i)] notasyonu, geçerli nesne [Me]'in i numaralı elemanını belirtir. Burada varsayılan indeksli özellik kullanılır. Dolayısıyla [Me(i)], [Me.Index(i)] ile eşdeğerdir.

Sınıf kodu, [lstpersonnes2.vb] dosyasına yerleştirilir ve derlenir:

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

Bir test programı oluşturulur:


' seçenekler
Option Explicit On 
Option Strict On

' ad alanları
Imports System
Imports System.Collections

Module test
    Sub Main()
        ' boş bir kişi listesi oluşturma
        Dim liste As listeDePersonnes = New listeDePersonnes
        ' kişilerin oluşturulması
        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)
        ' listenin doldurulması
        liste.Add(p1)
        liste.Add(p2)
        liste.Add(e1)
        ' listenin görüntülenmesi
        Console.Out.WriteLine(liste.ToString)
        ' kişi dışındaki bir nesnenin eklenmesi
        Try
            liste.Add(4)
        Catch e As Exception
            Console.Error.WriteLine(e.Message)
        End Try
    End Sub
End Module

Derlenir:

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

ve ardından şu komut çalıştırıldı:

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

Şöyle yazmak isteyebiliriz

dim p as personne=l("nom")

burada l, [listeDePersonnes] türünde olacaktır. Burada, l listesini artık bir öğe numarasıyla değil, bir kişi adıyla indekslemek istiyoruz. Bunun için varsayılan olarak indekslenen yeni bir özellik tanımlıyoruz:


    ' başka bir indeksleyici
    Default Public Shadows ReadOnly Property Item(ByVal N As String) As Integer
        Get
            ' N adlı kişi aranıyor
            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

İlk satır


    Default Public Shadows ReadOnly Property Index(ByVal N As String) As Integer

, varsayılan olarak indekslenen yeni bir özellik oluşturulduğunu gösterir. Tüm varsayılan özellikler aynı adı taşımalıdır; burada bu isim [Index]'tir. Yeni [Index] özelliği, listeDePersonnes sınıfını N karakter dizisiyle indeksler. listeDePersonnes(N) ifadesinin sonucu bir tamsayıdır. Bu tamsayı, N adını taşıyan kişinin listedeki konumunu gösterir; bu kişi listede yoksa -1 değerini verir. Yalnızca get özelliği tanımlanır; böylece listeDePersonnes yazımı engellenir ("nom")=valeur ise set özelliğinin tanımlanmasını gerektirecekti). Bu nedenle [ReadOnly] anahtar sözcüğü kullanılır. [Shadows] anahtar sözcüğü, temel sınıfın varsayılan özelliğini gizlemek için gereklidir (aynı imzaya sahip olmasa da).

get işlevinin gövdesinde, parametre olarak geçirilen N adını bulmak için kişi listesi taranır. Eğer i konumunda bulunursa i değeri döndürülür, aksi takdirde -1 döndürülür.

Yeni bir test programı şu şekilde olabilir:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

' test sayfası
Module test
    Sub Main()
        ' kişi listesi
        Dim l As New listeDePersonnes
        ' kişi ekleme
        l.Add(New personne("jean", "dumornet", 10))
        l.Add(New personne("pauline", "duchemin", 12))
        ' görüntüleme
        Console.Out.WriteLine(("l=" + l.ToString))
        l.Add(New personne("jacques", "tartifume", 27))
        Console.Out.WriteLine(("l=" + l.ToString))
        ' 1. öğeyi değiştirme
        l(1) = New personne("sylvie", "cachan", 5)
        ' 1. öğeyi görüntüleme
        Console.Out.WriteLine(("l[1]=" + l(1).ToString))
        ' liste görüntüleme l
        Console.Out.WriteLine(("l=" + l.ToString))
        ' kişi arama
        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

Çalıştırıldığında şu sonuçlar elde edilir:

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. Yapılar

VB.NET yapısı, doğrudan C dilinin yapısından türetilmiştir ve sınıfa çok yakındır. Bir yapı şu şekilde tanımlanır:


Structure spersonne
' özellikler
    ...
' özellikler
...
' yapıcılar
...
' yöntemler
End Structure

Beyan şekilleri benzer olsa da, sınıf ve yapı arasında önemli farklılıklar vardır. Örneğin, yapılarda miras kavramı yoktur. Türetilmemesi gereken bir sınıf yazarsak, ikisi arasında seçim yapmamıza yardımcı olacak yapı ve sınıf arasındaki farklar nelerdir? Bunu öğrenmek için aşağıdaki örneği inceleyelim:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

' spersonne yapısı
Structure spersonne
    Public nom As String
    Public age As Integer
End Structure

' csersonne sınıfı
Class cpersonne
    Public nom As String
    Public age As Integer
End Class

' bir test modülü
Public Module test
    Sub Main()
        ' bir kişi p1
        Dim sp1 As spersonne
        sp1.nom = "paul"
        sp1.age = 10
        Console.Out.WriteLine(("sp1=spersonne(" & sp1.nom & "," & sp1.age & ")"))
        ' bir kişi p2
        Dim sp2 As spersonne = sp1
        Console.Out.WriteLine(("sp2=spersonne(" & sp2.nom & "," & sp2.age & ")"))
        ' sp2 değiştirildi
        sp2.nom = "nicole"
        sp2.age = 30
        ' sp1 ve sp2'nin doğrulanması
        Console.Out.WriteLine(("sp1=cpersonne(" & sp1.nom & "," & sp1.age & ")"))
        Console.Out.WriteLine(("sp2=cpersonne(" & sp2.nom & "," & sp2.age & ")"))

        ' bir kişi cp1
        Dim cp1 As New cpersonne
        cp1.nom = "paul"
        cp1.age = 10
        Console.Out.WriteLine(("cP1=cpersonne(" & cp1.nom & "," & cp1.age & ")"))
        ' bir cpersonne P2
        Dim cp2 As cpersonne = cp1
        Console.Out.WriteLine(("cP2=cpersonne(" & cp2.nom & "," & cp2.age & ")"))
        ' P2 değiştirildi
        cp2.nom = "nicole"
        cp2.age = 30
        ' P1 ve P2'in doğrulanması
        Console.Out.WriteLine(("cP1=cpersonne(" & cp1.nom & "," & cp1.age & ")"))
        Console.Out.WriteLine(("cP2=cpersonne(" & cp2.nom & "," & cp2.age & ")"))
    End Sub
End Module

Bu programı çalıştırdığımızda şu sonuçlar elde edilir:

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)

Bu bölümün önceki sayfalarında personne sınıfı kullanılırken, artık spersonne yapısını kullanıyoruz:


' kişi yapısı
Structure spersonne
    Public nom As String
    Public age As Integer
End Structure

Beyanname


        Dim sp1 As spersonne

bir yapı (ad, yaş) oluşturur ve sp1'in değeri bu yapının kendisidir.

Aşağıdaki tanımlama


        Dim cp1 As New cpersonne

bir [cpersonne] nesnesi oluşturur (kabaca bizim yapımızın karşılığı) ve cp1 ise bu nesnenin adresi (referansı) olur.

Özetleyelim

  • yapı söz konusu olduğunda, sp1'in değeri yapının kendisidir
  • sınıf söz konusu olduğunda, p1'in değeri oluşturulan nesnenin adresidir

Programda şu kod yazıldığında


        Dim sp2 As spersonne = sp1

yazıldığında, yeni bir yapı (ad, yaş) oluşturulur ve p1 değeri, yani yapının kendisi ile başlatılır.

Böylece sp1'deki yapı sp2'ye kopyalanır. Bu, değerlerin kopyalanmasıdır.

Şu komut


        Dim cp2 As cpersonne = cp1

farklı şekilde çalışır. cp1'in değeri cp2'ye kopyalanır, ancak bu değer aslında nesnenin adresi olduğu için nesne kopyalanmaz. Sadece nesneye iki referans eklenir:

Yapı durumunda, sp2 değerini değiştirirsek, sp1 değerini değiştirmiş olmayız; program da bunu göstermektedir. Nesne durumunda ise, cp2 tarafından işaret edilen nesne değiştirilirse, cp1 tarafından işaret edilen nesne de aynı olduğu için değiştirilir. Programın sonuçları da bunu göstermektedir.

Dolayısıyla bu açıklamalardan şunu çıkarabiliriz:

  • yapı türündeki bir değişkenin değeri, yapının kendisidir
  • nesne türündeki bir değişkenin değeri, işaret edilen nesnenin adresidir

Bu temel fark anlaşıldıktan sonra, yapı, aşağıdaki yeni örnekte de görüldüğü gibi sınıfa çok benzemektedir:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

' kişi yapısı
Structure personne
    ' özellikler
    Private _nom As String
    Private _age As Integer

    ' özellikler
    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

    ' Oluşturucu
    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

' bir test modülü
Module test
    Sub Main()
        ' bir kişi p1
        Dim p1 As New personne("paul", 10)
        Console.Out.WriteLine(("p1=" & p1.ToString))
        ' bir kişi p2
        Dim p2 As personne = p1
        Console.Out.WriteLine(("p2=" & p2.ToString))
        ' p2 değiştirildi
        p2.nom = "nicole"
        p2.age = 30
        ' p1 ve p2'nin doğrulanması
        Console.Out.WriteLine(("p1=" & p1.ToString))
        Console.Out.WriteLine(("p2=" & p2.ToString))
    End Sub
End Module

Aşağıdaki yürütme sonuçları elde edilir:

p1=personne(paul,10)
p2=personne(paul,10)
p1=personne(paul,10)
p2=personne(nicole,30)

Burada yapı ile sınıf arasındaki tek belirgin fark, bir sınıf kullanıldığında p1 ve p2 nesnelerinin programın sonunda p2'nin değeriyle aynı değere sahip olacağıdır.

3.5. Arayüzler

Bir arayüz, bir sözleşme oluşturan yöntem veya özellik prototiplerinden oluşan bir kümedir. Bir arayüzü uygulamaya karar veren bir sınıf, arayüzde tanımlanan tüm yöntemlerin bir uygulamasını sağlamayı taahhüt eder. Bu uygulamayı denetleyen derleyicidir. Örneğin, Istats arayüzünün tanımı şöyledir:

Public Interface Istats
    Function moyenne() As Double
    Function écartType() As Double
End Interface

Bu arayüzü uygulayan tüm sınıflar şu şekilde tanımlanacaktır:

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] ve [écartType] yöntemleri C sınıfında tanımlanmalıdır. Aşağıdaki kodu ele alalım:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

' yapı
Public Structure élève
    Public _nom As String
    Public _note As Double

    ' yapıcı
    Public Sub New(ByVal NOM As String, ByVal NOTE As Double)
        Me._nom = NOM
        Me._note = NOTE
    End Sub
End Structure

' sınıf notları
Public Class notes
    ' özellik
    Protected _matière As String
    Protected _élèves() As élève

    ' üretici
    Public Sub New(ByVal MATIERE As String, ByVal ELEVES() As élève)
        ' öğrenci ve ders bilgileri
        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
        ' tüm notları birleştiriyoruz
        For i = 0 To (_élèves.Length - 1) - 1
            valeur &= "[" & _élèves(i)._nom & "," & _élèves(i)._note & "],"
        Next i
        'son not
        If _élèves.Length <> 0 Then
            valeur &= "[" & _élèves(i)._nom & "," & _élèves(i)._note & "]"
        End If
        valeur += ")"
        ' son
        Return valeur
    End Function
End Class

notes sınıfı, bir dersteki sınıf notlarını bir araya getirir:


Public Class notes
     ' özellik
    Protected _matière As String
    Protected _élèves() As élève

Özellikler, türetilmiş bir sınıftan erişilebilir olması için protected olarak tanımlanmıştır. élève türü, öğrencinin adını ve o dersteki notunu depolayan bir yapıdır:


Public Structure élève
    Public _nom As String
    Public _note As Double

     ' oluşturucu
    Public Sub New(ByVal NOM As String, ByVal NOTE As Double)
        Me._nom = NOM
        Me._note = NOTE
    End Sub    
End Structure

Bu notes sınıfını, notların ortalaması ve standart sapması olmak üzere iki ek özniteliğe sahip notesStats sınıfına dönüştürmeye karar veriyoruz:


Public Class notesStats
    Inherits notes
    Implements Istats

     ' özellikler
    Private _moyenne As Double
    Private _écartType As Double

notesStats sınıfı, aşağıdaki Istats arayüzünü uygular:

Public Interface Istats
    Function moyenne() As Double
    Function écartType() As Double
End Interface

Bu, notesStats sınıfının, moyenne ve écartType adlı iki yönteme sahip olması ve bu yöntemlerin imzalarının Istats arayüzünde belirtilen şekilde olması gerektiği anlamına gelir. notesStats sınıfı şu şekildedir:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

Public Class notesStats
    Inherits notes
    Implements Istats

    ' özellikler
    Private _moyenne As Double
    Private _écartType As Double

    ' oluşturucu
    Public Sub New(ByVal MATIERE As String, ByVal ELEVES() As élève)
        MyBase.New(MATIERE, ELEVES)
        ' not ortalaması hesaplama
        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
        ' standart sapma
        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 arayüzü yöntemleri
    Public Function moyenne() As Double Implements Istats.moyenne
        ' not ortalamasını verir
        Return _moyenne
    End Function

    Public Function écartType() As Double Implements Istats.écartType
        ' standart sapmayı hesaplar
        Return _écartType
    End Function
End Class

_moyenne ortalaması ve _ecartType standart sapması, nesnenin oluşturulduğu anda hesaplanır. Bu nedenle, moyenne ve écartType yöntemleri, yalnızca _moyenne ve _ecartType özniteliklerinin değerlerini döndürür. Öğrenci tablosu boşsa, her iki yöntem de -1 değerini döndürür.

Aşağıdaki test sınıfı:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

Module test
    Sub Main()
        ' bazı öğrenciler ve notlar
        Dim ELEVES() As élève = {New élève("paul", 14), New élève("nicole", 16), New élève("jacques", 18)}
        ' bunların bir not nesnesine kaydedilmesi
        Dim anglais As New notes("anglais", ELEVES)
        ' ve görüntülenir
        Console.Out.WriteLine((anglais.ToString))
        ' aynı işlem, ortalama ve standart sapma ile
        anglais = New notesStats("anglais", ELEVES)
        Console.Out.WriteLine((anglais.ToString))
    End Sub
End Module

şu sonuçları verir:

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 sınıfı, moyenne ve écartType yöntemlerini, Istats arayüzünü uyguladığını belirtmeden kendi başına gayet iyi bir şekilde uygulayabilirdi. Arayüzlerin ne gibi bir faydası vardır? Şu şekildedir: Bir işlev, I arayüzünün türüne sahip bir veriyi biçimsel parametre olarak kabul edebilir. Böylece, I arayüzünü uygulayan C sınıfına ait herhangi bir nesne, bu işlevin gerçek parametresi olabilir. Aşağıdaki örneği ele alalım:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

' bir Iexample arayüzü
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

' birinci sınıf
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

'ikinci sınıf
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 arayüzü, ajouter ve soustraire adlı iki yöntem tanımlar. classe1 ve classe2 sınıfları bu arayüzü uygular. Örneği basitleştirmek amacıyla bu sınıfların başka hiçbir şey yapmadığına dikkat edilmelidir. Şimdi şu örneği ele alalım:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

' test sınıfı
Module test

    'hesapla
    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 işlevi
    Sub Main()
        ' sınıf1 ve sınıf2 adlı iki nesnenin oluşturulması
        Dim c1 As New classe1
        Dim c2 As New classe2
        ' calculer statik işlevinin çağrılması
        calculer(4, 3, c1)
        calculer(14, 13, c2)
    End Sub
End Module

calculer işlevi, Iexemple türünde bir öğeyi parametre olarak kabul eder. Dolayısıyla bu parametre için hem classe1 hem de classe2 türünde bir nesne alabilir. Main yordamında bu işlem gerçekleştirilir ve aşağıdaki sonuçlar elde edilir:

17
21
127
201

Görüldüğü üzere, burada sınıflar için ele alınan polimorfizme benzer bir özellik söz konusudur. Eğer birbirleriyle miras yoluyla bağlantılı olmayan (dolayısıyla miras polimorfizmi kullanılamayan) bir Ci sınıflar kümesi, aynı imzaya sahip bir yöntemler kümesi sunuyorsa, bu yöntemleri ilgili tüm sınıfların miras alacağı bir I arayüzünde bir araya getirmek faydalı olabilir. Bu Ci sınıflarının örnekleri, I türünde bir parametre kabul eden fonksiyonların parametreleri olarak kullanılabilir, c.a.d. Bu fonksiyonlar, farklı Ci sınıflarının kendine özgü özelliklerini ve yöntemlerini değil, yalnızca I arayüzünde tanımlanan Ci nesnelerinin yöntemlerini kullanır. Son olarak, arayüzlerden çoklu miras alınabileceğini belirtelim, c.a.d. Şu şekilde yazılabilir:


Public Class classe
    Implements I1,I2,...

burada Ij'ler arayüzlerdir.

3.6. Ad alanları

Ekrana bir satır yazmak için şu komutu kullanırız:

Console.Out.WriteLine(...)

Console sınıfının tanımına bakarsak


Namespace: System
Assembly: Mscorlib (in Mscorlib.dll)

gördüğümüz gibi, bu sınıf System ad alanının bir parçasıdır. Bu, Console sınıfının System.Console olarak adlandırılması gerektiği anlamına gelir ve aslında şöyle yazmamız gerekir:

System.Console.Out.WriteLine(...)

Bunu, imports cümlesini kullanarak önleyebiliriz:

imports System
...
Console.Out.WriteLine(...)

System ad alanının, imports cümlesi ile içe aktarıldığı söylenir. Derleyici bir sınıf adına (burada Console) rastladığında, imports cümleleriyle içe aktarılan çeşitli ad alanlarında bu sınıfı arayacaktır. Burada, System ad alanında Console sınıfını bulacaktır. Şimdi, Console sınıfına ekli ikinci bilgiye dikkat edelim:


Assembly: Mscorlib (in Mscorlib.dll)

Bu satır, Console sınıfının tanımının hangi "derlemede" bulunduğunu gösterir. Visual Studio.NET dışında derleme yaparken ve kullanılması gereken sınıfları içeren farklı dll'lerin referanslarını belirtmek gerektiğinde bu bilgi yararlı olabilir. Bir sınıfın derlenmesi için gerekli olan dll'lere referans vermek için şu şekilde yazılır:

vbc /r:fic1.dll /r:fic2.dll ... prog.vb

Bir sınıf oluşturulurken, bu sınıf bir ad alanı içinde oluşturulabilir. Bu ad alanlarının amacı, örneğin sınıflar satıldığında sınıflar arasında ad çakışmalarını önlemektir. Sırasıyla dll, E1.dll ve E2.dll paketlerinde dağıtılan sınıfları dağıtan iki şirket olduğunu varsayalım. C adlı bir müşteri, her iki şirketin de personne sınıfını tanımladığı bu iki sınıf kümesini satın alsın. C adlı müşteri, bir programı şu şekilde derler:

vbc /r:E1.dll /r:E2.dll prog.vb

prog.vb kaynak dosyası personne sınıfını kullanıyorsa, derleyici, personne sınıfını E1.dll'ten mi yoksa E2.dll'ten mi alması gerektiğini bilemeyecektir. Bir hata bildirir. Eğer E1 şirketi sınıflarını E1 adlı bir ad alanında, E2 şirketi ise E2 adlı bir ad alanında oluşturursa, o zaman her iki personne sınıfı, sırasıyla E1.personne ve E2.personne olarak adlandırılacaktır. Müşteri, sınıflarında ya E1.personne ya da E2.personne'i kullanmalıdır, ancak personne'i kullanmamalıdır. Ad alanı, belirsizliği ortadan kaldırmaya yarar. Bir ad alanında sınıf oluşturmak için şu şekilde yazılır:


Namespace istia.st
    Public Class personne
        ' sınıfın tanımlanması
...
  end Class
end Namespace

Örnek olarak, daha önce incelediğimiz personne sınıfımızı bir ad alanında oluşturalım. Ad alanı olarak istia.st'i seçeceğiz. personne sınıfı şu şekilde olur:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

' istia.st ad alanının oluşturulması
Namespace istia.st
    Public Class personne
        ' özellikler
        Private prenom As String
        Private nom As String
        Private age As Integer

        ' yöntem
        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

        ' yöntem
        Public Sub identifie()
            Console.Out.WriteLine((prenom & "," & nom & "," & age))
        End Sub
    End Class
End Namespace

Bu sınıf, personne.dll olarak derlenir:

dos>dir
11/03/2004  18:27               610 personne.vb
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>dir
12/03/2004  18:06             3 584 personne.dll
11/03/2004  18:27               610 personne.vb

Şimdi personne sınıfını bir test sınıfında kullanalım:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System
Imports istia.st

' pg testi
Public Module test
    Sub Main()
        Dim p1 As New personne
        p1.initialise("Jean", "Dupont", 30)
        p1.identifie()
    End Sub
End Module

Şunu yazmaktan kaçınmak için


        Dim p1 As New istia.st.personne

yazmak zorunda kalmamak için, istia.st ad alanını bir imports cümlesiyle içe aktardık:


Imports istia.st

Şimdi test programını derleyelim:

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

Bu işlem, test.exe adlı bir dosya oluşturur ve bu dosya çalıştırıldığında aşağıdaki sonuçlar elde edilir:

Jean,Dupont,30

3.7. IMPOTS örneği

Bir önceki bölümde incelenen vergi hesaplamasını tekrar ele alalım ve bunu bir sınıf kullanarak işleyelim. Sorunu hatırlayalım:

Sadece maaşını beyan edecek bir vergi mükellefinin basitleştirilmiş durumunu ele alalım:

  • çalışanın pay sayısını şu şekilde hesaplıyoruz: nbParts = nbEnfants/2 + 1 (evli değilse), evliyse nbEnfants/2+2 olarak hesaplanır; burada nbEnfants, çocuk sayısıdır.
  • En az üç çocuğu varsa, yarım pay daha eklenir
  • vergilendirilebilir geliri R=0,72*S olarak hesaplanır; burada S, yıllık maaşıdır
  • aile katsayısı QF = R/nbParts olarak hesaplanır
  • Vergisi I hesaplanır. Aşağıdaki tabloyu ele alalım:
12620,0
0
0
13190
0,05
631
15640
0,1
1290,5
24.740
0,15
2072,5
31810
0,2
3309,5
39.970
0,25
4900
48360
0,3
6898,5
55790
0,35
9316,5
92970
0,4
12106
127.860
0,45
16754,5
151250
0,50
23147,5
172.040
0,55
30710
195.000
0,60
39312
0
0,65
49062

Her satırda 3 alan vardır. I vergisini hesaplamak için, QF<=alan1 olan ilk satır aranır. Örneğin, QF=23000 ise şu satır bulunur:

    24740        0.15        2072.5

bulunur. I vergisi bu durumda 0,15*R - 2072,5*nbParts'e eşittir. Eğer QF, QF<=alan1 ilişkisini hiçbir zaman karşılamıyorsa, o zaman son satırdaki katsayılar kullanılır. Burada:

    0                0.65        49062

bu da I=0,65*R - 49062*nbParts vergi tutarını verir.

impot sınıfı şu şekilde tanımlanacaktır:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System

Public Class impot
    ' vergi hesaplaması için gerekli veriler
    ' harici bir kaynaktan alınmıştır
    Private limites(), coeffR(), coeffN() As Decimal

    ' üretici
    Public Sub New(ByVal LIMITES() As Decimal, ByVal COEFFR() As Decimal, ByVal COEFFN() As Decimal)
        ' 3 tablonun da aynı boyutta olup olmadığı kontrol edilir
        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
        ' sorun yok
        Me.limites = LIMITES
        Me.coeffR = COEFFR
        Me.coeffN = COEFFN
    End Sub

    ' vergi hesaplaması
    Public Function calculer(ByVal marié As Boolean, ByVal nbEnfants As Integer, ByVal salaire As Long) As Long
        ' pay sayısının hesaplanması
        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
        ' Vergilendirilebilir gelir ve aile katsayısı hesaplaması
        Dim revenu As Decimal = 0.72D * salaire
        Dim QF As Decimal = revenu / nbParts
        ' vergi hesaplaması
        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

Bir vergi nesnesi, bir vergi mükellefinin vergisinin hesaplanmasına olanak tanıyan verilerle oluşturulur. Bu, nesnenin sabit kısmıdır. Bu nesne oluşturulduktan sonra, vergi mükellefinin medeni durumu (evli veya bekar), çocuk sayısı ve yıllık maaşına göre vergisini hesaplayan **calculer** yöntemini tekrar tekrar çağırabiliriz. Bir test programı şu şekilde olabilir:


' seçenekler
Option Strict On
Option Explicit On 

' ad alanları
Imports System
Imports Microsoft.VisualBasic

Module test
    Sub Main()
        ' etkileşimli vergi hesaplama programı
        ' kullanıcı klavyeden üç veri girer: evli nbEnfants maaş
        ' program daha sonra ödenecek vergiyi gösterir
        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"

        ' vergi hesaplaması için gerekli veri tabloları
        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}

        ' bir vergi nesnesinin oluşturulması
        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
        ' sonsuz döngü
        Dim marié As String
        Dim nbEnfants As Integer
        Dim salaire As Long
        While True
            ' vergi hesaplaması için parametreler isteniyor
            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()
            ' Yapılması gereken bir şey var mı?
            If paramètres Is Nothing OrElse paramètres = "" Then
                Exit While
            End If
            ' giriş satırındaki argüman sayısının kontrolü
            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
            ' parametrelerin geçerliliğinin kontrolü
            If Not erreur Then
                ' evli
                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
                ' maaş
                Try
                    salaire = Integer.Parse(args(2))
                    If salaire < 0 Then
                        Throw New Exception
                    End If
                Catch
                    erreur = True
                End Try
            End If
            ' parametreler doğruysa - vergi hesaplanır
            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

İşte önceki programın çalıştırılmasına ilişkin bir örnek:

dir>dir
12/03/2004  18:20             1 483 impots.vb
12/03/2004  18:21             2 805 test.vb
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 :