SANAL FONKSİYONLAR VE ÇOKBİÇİMLİLİK Yılmaz Kılıçaslan.

Slides:



Advertisements
Benzer bir sunumlar
C# - Metotlar.
Advertisements

Nesnelerin Özellikleri. - Üye nesneler - friend belirtesi - Nesnelerin operatörlere yüklenmesi - this yerel (lokal) değişkeni - inline tanımlı üye fonksiyonlar.
Göstericiler (Pointers)
SINIFLAR Yılmaz Kılıçaslan.
NESNEYE YÖNELİK PROGRAMLAMA SINIFLAR
NESNEYE YÖNELİK PROGRAMLAMA KALITIM
Yığın ve Kuyruk.
Nesneye Yönelik Programlama
Nesneye Dayalı Programlama
Nesneye Dayalı Programlama
C++’A GİRİŞ Yılmaz Kılıçaslan.
SANAL FONKSİYONLAR VE ÇOK BİÇİMLİLİK
String Kütüphanesindeki Arama Fonksiyonları
Bölüm 10 Yapılar ve Birleşimler
KOPYA YAPICI FONKSİYON, STATİK ELEMANLAR, ARKADAŞ SINIF VE FONKSİYONLAR, NESNE DİZİLERİ Yılmaz Kılıçaslan.
SINIFLAR GİRİŞ Yılmaz Kılıçaslan.
NESNEYE YÖNELİK PROGRAMLAMA
Nesneye Dayalı Programlama
DELEGATE OOP-UYG.
Erişim Denetimi, Fonksiyon
NESNE TABANLI PROGRAMLAMA -METOTLAR-
METODLAR.
KALITIM Yılmaz Kılıçaslan.
İSİM UZAYLARI (NAMESPACE)
SINIFLAR VE DİNAMİK BELLEK YÖNETİMİ
Sınıflar ve Fonksiyonlar
NESNE YÖNELİMLİ PROGRAMLAMA
Metotlar.
Nesne Yönelimli Programlama Dersi
FONKSİYONLAR.
SABİT NESNE VE ELEMAN FONKSİYONLAR VE ELEMAN NESNELER
METOTLAR.
Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü C ++ Nesne.
ÇOK BİÇİMLİLİK POLYMORPHISM
Nesneye Yönelik Programlama (12. Sunu). İsim Uzayları (Namespaces) Sınıfınızda Deniz adında iki öğrenci olduğunu kabul ediniz. Böyle bir durumda bu öğrencileri.
Diziler Adres Kavramı Nesnelerin Adresleri sizeof Operatörü
Kalıtım , Sınıf Asli Ergün.
Demet AYDIN METODLAR Demet AYDIN
Fonksiyonlar Fonksiyon Tanımı Değer Döndürmeyen Fonksiyonlar
Fonksiyonlar Fonksiyon Tanımı
Nesneye Dayalı Programlama
C++’a Giriş Yılmaz Kılıçaslan.
Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü ++ Bilişim Enstitüsü C ++ Veri.
SINIFLAR VE DİNAMİK BELLEK YÖNETİMİ VE SINIFLARIN DİĞER ÖZELLİKLERİ Yılmaz Kılıçaslan.
KALITIM Yılmaz Kılıçaslan.
Bölüm 6 Fonksiyonlar Fonksiyon Tanımı Değer Döndürmeyen Fonksiyonlar
C++.
SINIFLAR GİRİŞ Yılmaz Kılıçaslan. Sunum Planı  Bu derste sınıf mekanizmasını şu yönleriyle inceleyeceğiz: –Sınıf kavramının evrimine kısa bir bakış –Bir.
SINIFLAR ve NESNELER. İlk sınıfımızı ekleyelim class KrediHesap { public ulong HesapNo; public double Limit; public string KartSahibi; }
SINIFLAR VE DİNAMİK BELLEK YÖNETİMİ Yılmaz Kılıçaslan.
VERİ YAPILARI İşaretçi Nedir? Nesne Tabanlı Programlama.
SAÜ Bilgisayar Mühendisliği Dr. Cemil Öz
SAÜ Bilgisayar Mühendisliği Dr. Cemil Öz
Doç. Dr. Cemil Öz SAÜ Bilgisayar Mühendisliği Dr. Cemil Öz.
Veri yapıları Hafta3 Dizi Yapıları.
BİLGİSAYAR programlama II
Bilgisayar Programlama III C
Hafta2 Rekürsif Algoritmalar
Temel Veri Yapıları Veri Yapıları 1. Bölüm 1. 2 Programlarımızda tanımladığımız nesneler ya tek parçadan ya da birden fazla parçadan oluşurlar. Tek parçadan.
KALITIM(INHERITANCE) Öğr.Gör. Murat ASLANYÜREK. KALITIM KAVRAMINA GİRİŞ  Kalıtım, sınıflardan yeni sınıflar türetmeyi sağlar.  Türetilen yeni sınıflar,
İbrahim Olgaç PROGRAMLAMA DİLLERİ SUNUMU C#
Fonksiyonlar ve Diziler
Nesneye Dayalı Programlama
C’de Fonsiyonlar Aslı Ergün.
DİZİLER Bellekte sıralı bir şekilde bulunan ve aynı türden bilgilerin saklandığı veri yapısına dizi (array) denir. Örneğin kullanıcıdan 7 kişinin not ortalamasını.
YAPISAL PROGRAMLAMA Hafta-7
Kurucular(Yapıcılar), Yıkıcılar
Nesneye Dayalı Programlama 1
MTM216 GÖRSEL PROGRAMLAMA
NİŞANTAŞI ÜNİVERSİTESİ
Sunum transkripti:

SANAL FONKSİYONLAR VE ÇOKBİÇİMLİLİK Yılmaz Kılıçaslan

GİRİŞ C++, hem derleyici-zamanlı hem de çalışma-zamanlı çok biçimliliği destekler. Derleyici-zamanlı çok biçimlilik fonksiyonların veya operatörlerin aşırı yüklenmesi yoluyla gerçekleştirilir. Çalışma-zamanlı çok biçimlilik ise kalıtım ve sanal fonksiyon mekanizmaları aracılığıyla gerçekleştirilir.

TEMEL VE TÜRETİLMİŞ SINIFLAR ARASINDA DÖNÜŞÜM - 1 Bir satış elemanının aynı zamanda bir ücretli çalışan olması nedeniyle, bir UcretliCalisan nesnesine ihtiyaç duyduğumuz zaman bir SatisElemani nesnesi kullanabiliyor olmamız anlamlı olacaktır. Bu tarz bir ilişkiyi desteklemek için, C++ örtük olarak bir türetilmiş sınıf nesnesini bir temel sınıf nesnesine dönüştürür: UcretliCalisan isci; SatisElemani satici( “Ali Uzun” ); isci = satici; // SatisElemani => UcretliCalisan // turetilmis => temel Ters yönlü bir atama kabul edilmeyecektir: satici = isci; // Error; cannot convert

TEMEL VE TÜRETİLMİŞ SINIFLAR ARASINDA DÖNÜŞÜM - 2 Benzer şekilde, türetilmiş bir sınıf nesnesine işaret eden bir işaretçi örtük olarak bir temel sınıf nesnesine işaret eden bir işaretçiye dönüştürülebilir: Calisan *cPtr; UcretliCalisan isci( “Oya Kiper” ); SatisElemani satici( “Ali Uzun” ); Yonetici mudur( “Mehmet Demir “ ); cPtr = &isci;//UcretliCalisan * => Calisan * cPtr = &satici;//SatisElemani * => Calisan * cPtr = &mudur;//Yonetici * => Calisan *

TEMEL VE TÜRETİLMİŞ SINIFLAR ARASINDA DÖNÜŞÜM - 3 Bir nesneye işaretçi ile referansta bulunulduğu zaman hangi eleman fonksiyonun çağrılacağını işaretçinin tipi belirler. Eğer bir türetilmiş sınıf nesnesine bir temel sınıf işaretçisi ile işaret ederseniz yalnızca temel sınıfa ait fonksiyonları çağırabilirsiniz: SatisElemani satici( “Ali Uzun” ); SatisElemani *sPtr; UcretliCalisan *uPtr; sPtr = &satici; uPtr = &satici; uPtr->sureBelirle(40.0); //UcretliCalisan sPtr->ucretBelirle(6.0); //UcretliCalisan uPtr->satislariBelirle(1000.0); //Error sPtr->satislariBelirle(1000.0); //SatisElemani sPtr->komisyonBelirle(0.05); //SatisElemani float taban, toplam; taban = uPtr->odemeHesapla(); //UcretliCalisan toplam = sPtr->odemeHesapla(); //SatisElemani

TEMEL VE TÜRETİLMİŞ SINIFLAR ARASINDA DÖNÜŞÜM - 4 Türetilmiş bir sınıf işaretçisinin bir temel sınıf işaretçisine dönüştürülebilmesi, örneğin, bir çalışanlar topluluğu oluşturmamıza imkan verebilir: Class PersonelListesi {public: PersonelListesi(); ekle( Calisan *yeniPer ); // … }; PersonelListesi bolum1; UcretliCalisan *ucretliPtr; SatisElemani *saticiPtr; Yonetici *yoneticiPtr; // Yeni nesneler için bellek talebi ucretliPtr = new UcretliCalisan(“Ayse Suer” ); saticiPtr = new SatisElemani( “Ali Demir” ); yoneticiPtr = new Yonetici( “Mehmet Yilmaz” ); // Listeye ekleme bolum1.ekle( ucretliPtr ); bolum1.ekle( saticiPtr ); bolum1.ekle( yoneticiPtr ); Buradaki sorun her nesne yalnızca genel bir Calisan düzeyinde işleme tabi olabilir.

SANAL FONKSİYONLAR (sentaks) Sanal fonksiyon temel bir sınıfta bildirimi yapılan fakat türetilmiş bir sınıfta yeniden tanımlanmasını beklediğimiz bir eleman fonksiyondur. Bir sanal fonksiyon bildirimi temel sınıftaki eleman fonksiyon bildiriminin öncesine virtua l anahtar sözcüğünü yerleştirerek gerçekleştirilir. Global fonksiyonlar, arkadaş fonksiyonlar ve statik eleman fonksiyonlar sanal fonksiyon olamazlar. virtual anahtar sözcüğü, türetilmiş sınıflardaki bildirimler yada sınıf dışında tanımlanmış sanal fonksiyonlar için gerekli değildir; bir sanal fonksiyonun türetilmiş sınıflardaki versiyonları örtük olarak sanal bildirimlidirler. Türetilmiş sınıftaki sanal fonksiyon bildiriminde yada sınıf dışındaki sanal fonksiyon tanımında virtual anahtar sözcüğünü kullanmak derleyici tarafından bir hata olarak yorumlanmaz.

SANAL FONKSİYONLAR (semantik) “Normal” bir erişimde, sanal fonksiyonlar diğer bütün sınıfa ait eleman fonksiyonlar gibi davranırlar. Fakat, sanal fonksiyonları önemli kılan ve çalışma zamanlı çok biçimliliği desteklemesini sağlayan bir işaretçi ya da referans ile erişilmeleri halindeki davranışlarıdır. Eğer bir temel sınıf işaretçisi ya da referansı bu temel sınıftan türetilmiş bir sınıfın nesnesine işaret ediyorsa / referansta bulunuyorsa, sıradan fonksiyonlarda olmasını beklediğimizin tersine, C++ sanal bir fonksiyonun hangi versiyonunu çağıracağına nesneye bakarak karar verir. Bu karar çalışma zamanında gerçekleştirilir. Dolayısıyla, farklı nesnelere işaret edildiğinde / referansta bulunulduğunda fonksiyonun farklı versiyonları çalıştırılacaktır.

SANAL FONKSİYONLAR (örnek) //Sanal odemeHesapla fonksiyonlu calisan sinif hiyerarsisi class Calisan { public: Calisan( const char *nm ); char *isimSoyle() const; virtual float odemeHesapla() const; virtual ~Calisan() {} private: char isim[30]; }; class UcretliCalisan : public Calisan { public: UcretliCalisan( const char *nm ); void ucretBelirle( float ucrt ); void sureBelirle( float st ); float odemeHesapla() const; // sanal (ortuk) private: float ucret; float saat; };

SANAL FONKSİYONLAR (örnek) class SatisElemani : public UcretliCalisan { public: SatisElemani( const char *nm ); void komisyonBelirle( float kom ); void satislariBelirle( float satislar ); float odemeHesapla() const; // sanal (ortuk) private: float komisyon; float satisMiktari; }; class Yonetici : Calisan { public: Yonetici( const char *nm ); void maasBelirle( float maas ); float odemeHesapla() const; // sanal (ortuk) private: float haftalikMaas; };

SANAL FONKSİYONLAR (örnek) Her sınıfın kendisine ait odemeHesapla fonksiyonunun tanımı değişmeden kalabilir. Fakat, temel sınıfa eklenen odemeHesapla fonksiyonu için bir tanım gerekmektedir: float Calisan::odemeHesapla() const { cout << “Hesaplama islemi tanimlanmamis\n”; return 0.0; } Bu fonksiyon eğer salt bir Calisan nesnesi kullanıldığında ya da türetilmiş sınıflardan bir tanesi kendi odemeHesapla fonksiyonunu tanımlamamış ise çağrılır. // Bir Calisan isaretcisi ile odemeHesapla cagrimi Calisan *cPtr; float ucret; cPtr = &isci; ucret = cPtr->odemeHesapla(); //UcretliCalisan cPtr = &satici; ucret = cPtr->odemeHesapla(); //SatisElemani cPtr = &mudur; ucret = cPtr->odemeHesapla(); //Yonetici Eğer odemeHesapla sanal bildirimli olmasaydı, her fonksiyon çağrımı, 0.0 değerini döndüren Calisan::odemeHesapla fonksiyonunu çalıştıracaktı. Fakat, verilen çağrımların aynı olmasına rağmen çalıştırılacak fonksiyonlar farklı olacaktır.

SANAL FONKSİYONLAR (örnek) // Bir baska ornek #include using namespace std; class temel { public: virtual void sanalFonk() {cout << “Temel sinif – sanalFonk\n”;} }; class turetilmis1 : public temel { public: void sanalFonk() {cout << “Turetilmis sinif1 – sanalFonk\n”;} }; class turetilmis2 : public temel { public: void sanalFonk() {cout << “Turetilmis sinif2 – sanalFonk\n”;} };

SANAL FONKSİYONLAR (örnek) int main() { temel *p, b; turetilmis1 d1; turetilmis2 d2; p = &b; p->sanalFonk(); p = &d1; p->sanalFonk(); p = &d2; p->sanalFonk(); return 0; } Program çıktısını belirleyiniz.

SANAL FONKSİYONLAR (örnek) Program çıktısı: Temel sinif – sanalFonk Turetilmis sinif1 – sanalFonk Turetilmis sinif2 – sanalFonk “Normal” yolla sanal fonksiyon çağrımı: d2.sanalFonk; // turetilmis2::sanalFonk

SANAL FONKSİYONLAR ve AŞIRI YÜKLEME İlk bakışta benzer görünmesine karşın sanal bir fonksiyonun türetilmiş bir sınıfta yeniden tanımlanması fonksiyonların aşırı yüklenmesi (“function overloading”) işleminden farklıdır. Farkı belirtiniz.

SANAL FONKSİYONLAR ve REFERANSLAR - 1 // Temel sinif referansi ile sanal fonksiyon erisimi #include using namespace std; class temel { public: virtual void sanalFonk() {cout << “Temel sinif – sanalFonk\n”;} }; class turetilmis1 : public temel { public: void sanalFonk() {cout << “Turetilmis sinif1 – sanalFonk\n”;} }; class turetilmis2 : public temel { public: void sanalFonk() {cout << “Turetilmis sinif2 – sanalFonk\n”;} };

SANAL FONKSİYONLAR ve REFERANSLAR - 2 // Temel sinif referansini parametre alan fonksiyon void f(temel &r) {r.sanalFonk() ; } int main() { temel b; turetilmis1 d1; turetilmis2 d2; f(b); f(d1); f(d2); return 0; } Program çıktısını belirleyiniz.

Sanallık Kalıtımla Aktarılır - 1 Sanal bir fonksiyon kalıtıldığında, sanal doğası da kalıtılır: #include using namespace std; class temel { public: virtual void sanalFonk() {cout << “Temel sinif – sanalFonk\n”;} }; class turetilmis1 : public temel { public: void sanalFonk() {cout << “Turetilmis sinif1 – sanalFonk\n”;} }; class turetilmis2 : public turetilmis1 { public: void sanalFonk() {cout << “Turetilmis sinif2 – sanalFonk\n”;} };

Sanallık Kalıtımla Aktarılır - 2 int main() { temel *p, b; turetilmis1 d1; turetilmis2 d2; p = &b; p->sanalFonk(); p = &d1; p->sanalFonk(); p = &d2; p->sanalFonk(); return 0; } Bu kez, turetilmis2 adlı sınıf temel adlı sınıftan değil turetilmis1 adlı sınıftan türetilmiştir ama sanalFonk yine sanal kalmıştır. Program çıktısını belirleyiniz.

Sanal Fonksiyonlar Hiyerarşiktir - 1 Eğer türetilmiş bir sınıf sanal bir fonksiyonu yeniden tanımlamaz ise bu sınıfın bir nesnesi sanal fonksiyona erişmek istediğinde temel sınıf tarafından tanımlanan versiyon kullanılır: #include using namespace std; class temel { public: virtual void sanalFonk() {cout << “Temel sinif – sanalFonk\n”;} }; class turetilmis1 : public temel { public: void sanalFonk() {cout << “Turetilmis sinif1 – sanalFonk\n”;} }; class turetilmis2 : public temel { public: // sanalFonk() yeniden tanimlanmamis. };

Sanal Fonksiyonlar Hiyerarşiktir - 2 int main() { temel *p, b; turetilmis1 d1; turetilmis2 d2; p = &b; p->sanalFonk(); p = &d1; p->sanalFonk(); p = &d2; p->sanalFonk(); return 0; } Program çıktısını belirleyiniz.

Sanal Fonksiyonlar Hiyerarşiktir - 3 Program çıktısı: Temel sinif – sanalFonk Turetilmis sinif1 – sanalFonk Temel sinif – sanalFonk Yukarıdaki program genel bir kuralın özel bir durumunu örneklemektedir. Kalıtım, C++’da hiyerarşik olarak tanımlandığı için, sanal fonksiyonlar da hiyerarşik olmalıdır. Bu ise, eğer türetilmiş sınıf sanal fonksiyonu yeniden tanımlamış ise tersinden hiyerarşik sıralamada ilk yeniden tanımlanmış fonksiyonun kullanılacağı anlamına gelir (bkz. bir sonraki örnek).

Sanal Fonksiyonlar Hiyerarşiktir - 4 #include using namespace std; class temel { public: virtual void sanalFonk() {cout << “Temel sinif – sanalFonk\n”;} }; class turetilmis1 : public temel { public: void sanalFonk() {cout << “Turetilmis sinif1 – sanalFonk\n”;} }; class turetilmis2 : public turetilmis1 { public: // sanalFonk() yeniden tanimlanmamis. };

Sanal Fonksiyonlar Hiyerarşiktir - 5 int main() { temel *p, b; turetilmis1 d1; turetilmis2 d2; p = &b; p->sanalFonk(); p = &d1; p->sanalFonk(); p = &d2; p->sanalFonk(); return 0; } Program çıktısını belirleyiniz.

Sanal Fonksiyonlar Hiyerarşiktir - 6 Program çıktısı: Temel sinif – sanalFonk Turetilmis sinif1 – sanalFonk

SAF SANAL FONKSİYONLAR - 1 Birçok durumda temel sınıftaki sanal fonksiyon için anlamlı bir tanım bulunmayabilir. Bu durumlarda saf sanal fonksiyonlar (“pure virtual functions”) kullanılır. Saf sanal fonksiyon temel sınıfta tanımı olmayan sanal fonksiyondur ve bildiriminin genel formu aşağıdaki gibidir: virtual tip fonksiyon-ismi(parametreler) = 0; Saf sanal fonksiyon türetilmiş bütün sınıflarda yeniden tanımlanmalıdır. Aksi, derleyici-zamanlı hataya yol açar. En az bir saf sanal fonksiyon içeren sınıfa soyut (“abstract”) sınıf denir. Soyut sınıflara ait nesne yaratılamaz ama soyut sınıflara işaret eden işaretçiler yada referansta bulunan referanslar yaratılabilir.

SAF SANAL FONKSİYONLAR - 2 #include using namespace std; class sayi { protected: int deger; public: void degerBelirle(int i) { deger = i;} virtual void goruntule() = 0; }; class hexTip : public sayi { public: void goruntule(){cout << hex << deger << “\n”;} }; class desTip : public sayi { public: void goruntule(){cout << deger << “\n”;} }; class oktTip : public sayi { public: void goruntule(){cout << oct << deger << “\n”;} };

SAF SANAL FONKSİYONLAR - 3 int main() { desTip d; hexTip h; oktTip o; d.degerBelirle(20); d.goruntule(); // 20 h.degerBelirle(20); h.goruntule(); // 14 o.degerBelirle(20); o.goruntule(); // 24 return 0; }

SANAL YIKICI FONKSİYONLAR Problem: Dinamik olarak yaratılmış nesneleri delete operatörü ile yok etmek potansiyel bir problem kaynağıdır. Eğer delete bir temel sınıf işaretçisine uygulanıyorsa, işaretçi türetilmiş bir sınıfın nesne işaret ediyor bile olsa, derleyici temel sınıfın yıkıcı fonksiyonunu çağıracaktır. Çözüm: Bu sorun temel sınıfın yıkıcı fonksiyonunu sanal yaparak çözülür. Bu şeklide, türetilmiş sınıfların yıkıcı fonksiyonları da sanal yapılmış olacaktır ve böylelikle delete operatörü temel sınıf işaretçisine uygulandığında ilgili yıkıcı fonksiyon çağrılacaktır. İlke olarak sanal fonksiyon içeren bir sınıf yazıldığında, sanal bir yıkıcı fonksiyon da tanımlanmalıdır. Yıkıcı fonksiyonların aksine, yapıcı fonksiyonlar sanal olarak tanımlanamaz.

STATİK VE DİNAMİK BAĞLAMA - 1 Fonksiyon çağırma işlemi ile çağrılan fonksiyon kodu arasında bağlantı kurulması işlemi “bağlama” olarak adlandırılır. Bağlama, genellikle derleme esnasında yapılan bir işlemdir. –fonksiyon çağırma komutları ile fonksiyon adresleri birbirine bağlanır; –Fonksiyon çağırma komutundan hangi fonksiyonun çağrılmak istendiğinin anlaşılması gerekir. Program içerisindeki fonksiyon çağıma komutlarından, hangi fonksiyonun çağrılmak istendiğine derleme aşamasında karar verilebilmesi “erken bağlama” veya “statik bağlama” olarak adlandırılır. Bağlama işleminin programın çalıştırılması esnasında yapılmasına “geç bağlama” veya “dinamik bağlama” denir. Bir fonksiyon işaretçisi fonksiyonun bellekteki adresini içerir. Fonksiyon ismi fonksiyona işaret eden bir sabit işaretçidir. –long (*fonksiyon) (int); –long *fonksiyon(int);

STATİK VE DİNAMİK BAĞLAMA - 2 #include using namespace std; int artan(int a, int b) { return a>b; } int azalan(int a, int b) { return a<b; } void yer_degistir(int &eleman1, int &eleman2) { int gecici; gecici = eleman1; eleman1 = eleman2; eleman2 = gecici; } void sirala( int *dizi, int boyut, int (*karsilastir)(int,int) ) { int i, j; for (i = 0; i < boyut; i++) for(j = i+1; j < boyut; j++) if ((*karsilastir)(dizi[i], dizi[j])) yer_degistir(dizi[i], dizi[j]); }

STATİK VE DİNAMİK BAĞLAMA - 3 int main() { int a[10] = {3,6,12,89,5,43,2,90,345,1}; int siralama; cout << “Artan siralama: 1 - Azalan siralama: 0 “; cin >> siralama; if ( siralama == 1 ) { sirala(a, 10, artan); cout << “Artan dizi: \n”;} else {sirala(a, 10, azalan);cout << “Azalan dizi: \n”;} for (int k = 0; k < 10; k++) cout << a[k] << “ “; return 0; }