nesneye dayal ı programlama

29
Harran Üniversitesi Bilgisaya r Mühendisliği Yrd.Doç.Dr.Nur ettin Beşli Nesneye Dayalı Programlama DERS 6

Upload: lucie

Post on 06-Jan-2016

75 views

Category:

Documents


3 download

DESCRIPTION

Nesneye Dayal ı Programlama. DERS 6. Türemiş Sınıflarda Bilinirlik Alanı. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Nesneye Dayalı Programlama

DERS 6

Page 2: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Türemiş Sınıflarda Bilinirlik Alanı Bilinirlik alanı (scope) bir ismin derleyici tarafından

tanınabildiği program aralığıdır. C ve C++ da bir blok içinde aynı isimli birden fazla değişken biliniyorsa o blok içinde aynı isimli değişken kullanıldığında dar bilinirlik alanına sahip olana erişilir.

Dar bilinirlik alanındaki isim kendisini kapsayan daha geniş bilinirlik alanında bulunan ismi maskeler.Onun görülmesini engeller.

Aynı kural C++’ da türetme işlemlerini kapsayacak biçimde geçerlidir.

Page 3: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Önce şu soruyu soralım: Türetme durumunda taban sınıf türemiş sınıf tarafından erişilebildiğine göre taban sınıftaki bir isim mi daha dar bilinirlik alanına sahiptir, türemiş sınıftaki bir isim mi?

Cevap: Türemiş sınıftaki isim. Çünkü taban sınıftaki isimler hem kendi sınıfı içinde hem de türemiş sınıf içinde kullanıldığına göre daha geniş bir bilinirlik alanına sahiptir.

Page 4: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Örnek:class Base {

protected:

int b;

public:

Base():b(0){}

void display()const;

};

#include <iostream>

void Base::display()const

{

std::cout << "b = " << b << std::endl;

}

class Der: public Base {

int b;

public:

Der():b(1){}

void set(int);

void display() const;

void func() const;

};

void Der::set(int val)

{

b = val; //Der::b = val;

}

void Der::display()const

{

std::cout << "b = " << b << std::endl;

}

void Der::func()const

{

display();

}

Page 5: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Burada Der sınıfının set üye işlevi içinde kullanılan b ismi, daha dar bilinirlik alanına sahip olan Der sınıfının b isimli elemanına ilişkindir.

Der sınıfının b isimli elemanı Base sınıfının b isimli elemanını maskeler yani görünmesini engeller.(Tabii eğer Der sınıfının b isimli bir elemanı olmasaydı burada kullanılan b, Base sınıfına ilişkin olurdu.)

Page 6: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Ayrıca Base sınıfının display üye işlevi içinde kullanılan b elemanı Base sınıfına ilişkin olandır. Zaten taban sınıf türemiş sınıfa erişemediğine göre hiçbir biçimde bunun Base sınıfına ilişkin olması söz konusu değildir.

Türemiş sınıf içinde aynı isimli taban sınıf elemanlarına ve işlevlerine çözünürlük işleci ile erişilebilir.

Page 7: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Örneğin bu kez Der sınıfının iki parametreli set isimli bir üye işlevi daha olduğunu düşünelim:

İşlevde doğrudan kullanılan b, bilinirlik alanı kurallarına göre Der sınıfına ilişkin olandır. Ancak çözünürlük işleci ile, yani Base::b ifadesi ile kullanılan b, Base sınıfına ilişkin olandır.

İki terimli çözünürlük işlecini taban ve türemiş sınıflarda aynı isimli elemanlar ya da işlevler varken taban sınıfın elemanlarına erişmek amacıyla bu biçimde kullanılabilir.

void Der::set(int x, int y)

{

b = x;

Base::b = y;

}

Page 8: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Bilinirlik alanı kuralları işlev isimleri için de geçerlidir. Türemiş ve taban sınıfta aynı isimli işlevler varsa dar bilinirlik alanı kuralına göre türemiş sınıftaki anlaşılır.

Örneğin Der sınıfının func işlevi içinde çağrılan display işlevi Der sınıfına ilşkin olandır.

Çözünürlük işleci, aynı amaçla üye işlevler için de kullanılabilir.

Page 9: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Örneğin türemiş sınıf olan Der sınıfının func isimli üye işlevi içinde bu kez taban sınıfın display isimli işlevi çağrılmak istenseydi bu aşağıdaki gibi yapılabilirdi:

Dar bilinirlik alanı kuralı dışarıdan sınıf elemanlarına erişirken de geçerlidir. Yukarıda verdiğimiz türetme işlemi için aşağıdaki kod yazılmış olsun:

void Der::func()

{

Base::display();

}

Page 10: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

int main()

{

Der der_object, *der_ptr;

der_object.display(); //1

der_object.Base::display(); //2

der_ptr = &der_object;

der_ptr->display(); //3

der_ptr->Base::display(); //4

Base base_object;

base_object.display(); //5

return 0;

}

Yukarıdaki main işlevinde yorum satırlarıyla işaretlenen işlev çağrılarına bakalım:

//1 Der sınıfının display işlevi çağrılır.

//2 Base sınıfının display işlevi çağrılır.

//3 Der sınıfının display işlevi çağrılır.

//4 Base sınıfının display işlevi çağrılır.

//5 Base sınıfının display işlevi çağrılır. Taban sınıf türemiş sınıfa erişemez!

Page 11: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Bilinirlik alanı ile erişilebilirlik aynı şeyler değildir. C++’da her zaman önce isim araması daha sonra erişim denetimi yapılır. Bu kuralın etkisini yandaki gibi bir türetme işleminde değerlendirelim:

class Base{

public:

int x;

};

class Der: public Base {

int x;

};

void func()

{

Der der_object;

der_object.x = 0; //Geçersiz!

}

Page 12: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

C++'a yeni başlayanlar func işlevi içindeki der_object.x = 0; atamasının geçerli olması gerektiğini düşünürler. “Hem türemiş sınıfta hem de taban sınıfta x isimli bir eleman

olduğuna göre, önce türemiş sınıfta bulunan x isimli elemana erişilmeye çalışılır. Türemiş sınıfta bulunan x sınıfın private bölümünde bulunduğu için bu erişim gerçekleşmez. Ancak taban sınıfın public bölümünde bulunan x’e erişilir.

Ancak durum böyle değildir. Önce isim araması yapılır. Türemiş sınıf olan Der sınıfının bilinirlik alanında x ismi bulunduğunda isim arama sona erdirilir. Aranan isim bulunmuş ve x isminin türemiş sınıf bilinirlik alanındaki x olduğu anlaşılmıştır. Artık ne nedenle olursa olsun yeniden bir isim araması yapılmaz. Şimdi bu x'e erişimin geçerli olup olmadığı sorgulanır. Türemiş sınıfın x isimli elemanı türemiş sınıfın private bölümünde olduğu için erişim geçersizdir.

Page 13: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Türemiş Sınıf İçinde Yapılan using Bildirimi Türemiş ve taban sınıfların farklı bilinirlik

alanı oluşturduklarını biliyorsunuz. Türemiş sınıf bilinirlik alanı içinde bildirilen bir isim, taban sınıf içinde de kullanılmışsa, taban sınıftaki isim maskelenir.

Maskelenme istenmiyorsa türemiş sınıf içinde using bildirimi yapılabilir. Sınıf içi using bildirimiyle taban sınıflara ilişkin maskelenen isimler görünür kılınır.

Page 14: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Böylece taban sınıf ve türemiş sınıf işlevleri farklı bilinirlik alanında olsalar bile yüklenebilir.

Yandaki kodu inceleyelim:

#include <iostream>

class Base {

public:

void foo(){std::cout << "Base::foo()" << std::endl;}

};

class Der: public Base {

public:

using Base::foo;

void foo(int){std::cout << "Der::foo(int)" << std::endl;}

};

int main()

{

Der der_object;

der_object.foo();

der_object.foo(25);

return 0;

}

Page 15: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Der sınıfının tanımı içinde yapılan using bildirimiyle Base sınıfının foo isimli işlevi Der sınıfı içinde görülebilir hale getiriliyor. Böylece:

der_object.foo();

çağrısı söz konusu olduğunda

void Base::foo();

işlevi de çağrıya aday işlev olarak belirlenir. using bildirimiyle taban ve türemiş sınıfın foo işlevleri ayrı bilinirlik alanlarına ait olmasalar da yüklenebilir.

Page 16: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Şimdi de aşağıdaki koda bakalım:

main işlevi içinde çağrılan, Der sınıfının foo işlevidir. Der sınıfının foo işlevinin gizli parametre değişkeni Der & türünden iken, Base sınıfının foo işlevinin gizli parametre değişkeni Base & türündendir.

#include <iostream>

class Base {

public:

void foo(){std::cout << "Base::foo()" << std::endl;}

};

class Der: public Base {

public:

using Base::foo;

void foo(){std::cout << "Der::foo()" << std::endl;}

};

int main()

{

Der der_object;

der_object.foo();

return 0;

}

Page 17: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Erişilebirliğin Tekrar Tanımlanması Taban sınıfının public üyelerinin erişilebilirliği

türemiş sınıf içerisinde yeniden tanımlanabilir. Private olarak miras alırsanız, taban sınıfın

bütün public üyeleri private olur.Bunlardan herhangi birinin görülebilir olmasını isterseniz, türemiş sınıfın public kısmında sadece isimlerinin başına using kelimesini kullanmanız yeterli.

Page 18: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

class Base{ private: int k; public: int i; void f();};class Derived : private Base{ // All members of Base are private now int m; public: using Base::f; // f() is public again , i is still private void fb1();};

int main(){ Base b; Derived d; b.i=5; // OK public in Base d.i=0; // ERROR private inheritance b.f(); // OK d.f(); // OK return 0;};

Page 19: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Atama operatörü ve miras Taban sınıfın atama operatörü, türemiş sınıfın atama operatörü olamaz.Örnek:

class String{ protected: int size; char *contents; public: const String & operator=(const String &); // assignment operator: // Other methods};

const String & String::operator=(const String &in_object){size = in_object.size;delete[ ] contents; // delete old contentscontents = new char[size+1];strcpy(contents, in_object.contents);return *this;}

Page 20: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

String2 sınıfı String sınıfından türemiştir.Eğer atama operatörü gerekliyse şu şekilde yazılmalıdır.

class String2 : public String{ // String2 is derived from String int size2; char *contents2; public: const String2 & operator=(const String2 &); // assignment operator for String2 : // Other methods}; // **** Assignment operator for String2 **** const String2 & String2::operator=(const String2 &in_object) { size = in_object.size; // inherited size delete[ ] contents; contents = new char[size + 1]; // inherited contents strcpy(contents, in_object.contents); size2 = in_object.size2; delete[ ] contents2; contents2 = new char[size2 + 1]; strcpy(contents2, in_object.contents2); return *this; }

Page 21: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Bir önceki örnekte, String(taban) sınıfın verileri protected olmalıdır. Aksi halde String2(türemiş) sınıfın metodları onlara erişemez.String2 sınıfı için atama operatörü yazmanın en iyi yolu, String(taban) sınıfın atama operatörünü çağırmaktır.

//** Assignment operator **const String2 & String2::operator=(const String2 & in_object){String::operator=(in_object); // call the operator= of String (Base)cout<< "Assignment operator of String2 has been invoked" << endl;size2 = in_object.size2;delete[] contents2;contents2 = new char[size2 + 1];strcpy(contents2, in_object.contents2);return *this;}

Page 22: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Çoklu Türetme (multiple inherritence) Bir sınıfın birden fazla taban sınıfa sahip

olması durumudur. Çoklu türetme durumunda başlangıç fonksiyonlarının çağrılması bildirimde ilk yazılan taban sınıfın başlangıç fonksiyonu önce çağrılacak biçimdedir.

Örneğin class C:public A, public B { böyle bir bildirimde önce a, b, c şeklinde başlangıç fonksiyonları çağrılır. Bitiş fonksiyonlarıda c, b, a olacak şekilde tam tersdir.

Page 23: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Türemiş sınıf nesnesi bütün taban sınıf nesnelerinide içerir. Taban sınıf nesnelerinin tüenmiş sınıf içindeki organizasyonu standart olarak belirlenmemiştir. Ancak bildirimde genllikle bildirimde ilk yazılan taban sınıfın veri elemanları düşük anlamlı adreste oacak biçimde ardışıl bir yerleşim söz konusudur.

Page 24: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Page 25: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Tekrarlı Taban Sınıflar

class Gparent

{ };

class Mother : public Gparent

{ };

class Father : public Gparent

{ };

class Child : public Mother, public Father

{ };

Page 26: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Mother ve Father sınıflarının ikiside Gparent sınıfından türemiştir, ve Child sınıfı Mother ve Father sınıflarından türemiştir.Hatırlayalım ki, her bir nesne miras yoluyla, taban sınıfın altnesnesini içererek yaratılır. Mother nesnesi ve Father nesnesi Gparent’in alt nesnelerini, Child nesnesi Mother and Father’ın alt nesnelerini, dolayısıyla Child nesnesi biri Mother’dan biri Father’dan türemiş, Gparentin iki alt nesnesini içerir

Page 27: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

class Gparent{ protected: int gdata;};Child’dan şu şekilde ulaşmaya çalışırsanız hata verir.class Child : public Mother, public Father{ public: void Cfunc() { int temp = gdata; // ERROR: ambiguous }};

Page 28: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Derleyici gdata’ya verilen referansın belirsiz oldugunu söyliyecektir.Hangi çeşit gdata’ya ulaşacağını bilemez, Gparent’dan miras alan Mother alt nesnesinden gelen gdata mı, yoksa Gparent’dan miras alan Father alt nesnesinden gelen gdatamı.

Page 29: Nesneye Dayal ı Programlama

Harran Üniversitesi Bilgisayar Mühendisliği Yrd.Doç.Dr.Nurettin Beşli

Sanal Taban Sınıflar

Virtual kelimesi kullanarak oluşturulur. Örneğin Mother ve Father Gparent’dan türeme yaparken:

class Gparent { }; class Mother : virtual public Gparent { };class Father : virtual public Gparent { };class Child : public Mother, public Father { }; Virtual kelimesi compilera sonradan gelen türemiş sınıflar içinden

sadece bir tanesinin alt nesnesinin miras alınmasını söyler. Bu belirsizlik problemini çözer.