Haberler:

Forum kuralları güncellendi LÜTFEN  okuyunuz:  https://bit.ly/2IjR3ME

Ana Menü

C++ Sınıflarla ilgili

Başlatan strom, 21 Aralık 2013, 01:20:17

strom

İyi günler herkese.
Keil kullanarak c++ programlama yapıyordum ve programlama esnasında aklıma bişey takıldı. Mesela şöyle bir class'ımız olsun;

Class PICPROJE
{
void f1()
{
//Bla bla bla
//......
}
void f2()
{
//Bla bla bla
//......
}
void f3()
{
//Bla bla bla
//......
}
}


3 fonksiyonunda birbirini çağırmadığını varsayıyoruz. Şimdide normal kodumuzun 2 farklı fonksiyonunda bu nesneler yaratılıyor olsun. Misal

void Ornek1()
{
PICPROJE pic1;
 pic1.f1();
}

void Ornek2()
{
PICPROJE pic2
pic2.f2();
pic2.f3();
}


Şimdi bildiğim kadarıyla fonksiyonun local değişkenleri, fonksyion çağrıldığı zaman stack içerisinde oluşturuluyor ve fonksiyondan çıkıldığında değişken yok ediliyor.
Eğer bu doğruysa şöyle bir sorum olacak; şimdi Ornek1 fonksiyonun içinde class'ın sadece f1 fonksiyonu çağrılıyor. Peki buna rağmen  f2 ve f3 fonksiyonlarıda oluşturulup stack'a yazılır mı? Derleyici bunun optimizasyonunu yapar mı?

Eğer tam ifade edemediysem özür dilerim. Umarım anlatabilmişimdir.

strom

#1
Hocam öncelikle cevabınız için çok teşekkr ederim. Bana ne kadar az şey bildiğimi tekrar hatırlattı :)
Öncelikle dediğiniz gibi class fonksiyonları code segmentte saklanıyormuş. Bunu görmek için keil ile bir takım denemeler yaptım. Elde ettiğim sonuç şu oldu; Class'taki fonksiyonlar sadece bir kere belleğe yazılıyor ve bu classtan oluşturulan bütün nesneler (global veya local farketmez), o birkere yazılan fonksiyonu çağırıyor.
Bu arada ilginç birşeye daha denk geldim. Bir fonksiyon tanımlıyorum ve çağırmıyorum. Buna rağmen keil bu fonksiyon için bellekte yer ayırıyor. Normalde kullanılmayan fonksiyonun derlenmesi gerekmiyor mu?

Meğer bu nesneler çok ayrı bir dünyaymış. En başta kavramsal olarak anlaşılması gerekiyor sanırım. Önce problemi sınıf olarak nasıl ifade edileceğini programı yazmadan önce tasarlamak gerekiyormuş anlaşılan. Daha sonra sınıflar arasında hiyerarşiyi, sınıflar arasındaki benzerliklere göre düzenleyeceksin. Mesela bir problemim var ve ben bunu nasıl sınıflandıracağımı kestiremiyorum. C'de modüler programlama diye bişey öğrenmiştik ve işlerimizi hallediyorduk. Şimdi ise durumlar çok karıştı. C++, sadece nesne oluşturup birbirine benziyon fonksiyonları tek bir çatı altında toplamakla olmuyormuş.
Daha baya bir yolumuz var anlaşılan. Tekrardan teşekkür ederim hocam.

mesaj birleştirme:: 22 Aralık 2013, 16:02:44

Bu arada hocam aklıma bişey takıldı. Şimdi madem bu fonksyionlar belleğe yazılıyor ve adresi değişmiyor. O zaman biz bu fonksiyonun adresini nasıl alabiliriz?
Amacım printf fonksiyonu için fputc fonksiyonunu override etmek. Ancak ekrana karakter basan fonksiyonum sınıf içerisinde ve ben fputc içerisinde yeni bir nesne tanımlamadan bu fonksiyona erişmek istiyorum. Bu konu hakkında bilginiz var mı acaba?

strom

Hocam inanın çok sevinirim. Dün bütün günümü c++ pointer-to-member function kavramına harcadım. Sonunda olayı kavradım sanırım. Olayı özetliim siz eksik, yanlış varsa tamamlayın.
Benim fputc içerisinde ekrana karakter gönderecek fonksiyonum bir sınıf içerisindeydi. Şuna benzer bir yapı;
extern "C"
{
int fputc(int ch, FILE * f)
{
	TEXT::Text(ch);
	return 0;
}

}


Aşağı yukarı böyle bir kullanım hedefliyordum. Ancak görüleceği üzere bu kullanım tamamen yanlış. Benim düşüncem şu şekildeydi; Madem class'ın içerisindeki fonksiyonların adresleri sabit ve derleme anında hafızaya yazılıyor, o zaman neden ben bu adrese direk erişemiyorum.
Bunun için araştırmaya koyuldum ve bazı ilginç şeyler buldum. İlk aklıma gelen şu kullanım oldu:

extern "C"
{
int fputc(int ch, FILE * f)
{
	(&TEXT::Text)(ch);
	return 0;
}

}


sonrada şu;

void (PAINT::*fText) (char);

extern "C"
{
int fputc(int ch, FILE * f)
{
        fText = &TEXT::Text;
	fText(ch);
	return 0;
}

}


Tabi sonuç olarak sürekli syntax hatası aldım. Amacım TEXT türünden bir nesne oluşturmadan fonksiyona erişmekti. Çünkü biliyorum bu adres derleme anında belleğe yazıldı ve ben buna ulaşabiliyor olmalıydım. Bunu takıntı haline getirmiştim artık. En sonunda okuduğum makalelerden anladımki böyle bir kavram yokmuş (neden olmadığınıda anladım tabi)
Daha sonra şöyle ilginç birşey öğrendim;
extern "C"
{
int fputc(int ch, FILE * f)
{
        TEXT *text;
	text->Text(ch);
	return 0;
}

}


Bu ilginç ve bir o kadar anlamsız ifade nedense sonuç verdi ve Text fonksiyonuna ulaştım. İşte tam bu noktada neden direk olarak sınıfın fonksiyonuna erişmenin olmadığını ve bunun neden anlamsız olduğunu farkettim. Öncelikle haklıydım. Fonksiyonlara ulaşılabiliniyordu. Yoksa nasıl boş bir pointer'dan class'ın fonksiyonuna erişebileyim. Demekki derleyici bu fonksiyonların adresini biliyor. Aslında burdaki saçma bulduğum şey şu oldu; madem bu şekilde ulaşabiliyorum, o zaman neden bunun için bir ifade yok. Boşuna bir pointer tanımlıyorum? Gerçi ztn böyle bir olayın anlamsız olduğunu gördükten sonra bunun üstünde durmadım. Gelelim niye anlamsızdı.
Evet fonksiyona gittim. Fakat malesefki Text fonksiyonun içinde class'ın değişkenlerine erişemedim. Daha doğrusu eriştim ama bu değişkenlerde bir değer yoktu!!! (Ztn olması gereken buydu. Bu noktada ne kadar aptalca birşey istediğimi farkettim. Birincisi bu değerlere nasıl erişecektimki. Tanımlanmamışlardı bile daha. Bİr bellek alanı tahsis edilmemişti. Aslında benim düşüncem şuydu; Main içerisinde benim bir TEXT sınıfından türemiş bir nesnem var ve ben bu nesnenin değişkenlerine bir değer atadım. O zaman ben main'in dışında da bu fonksiyonu çağırabilirsem istediğimi elde edeceğim. Tabi ne kadar aptalca bişey istediğimi o dakika farkettim. Ancak iyiki böyle bişey istemişim çünkü bu sayede hem sınıfları daha iyi kavradım hem de c++ konusunda ne kadar eksik olduğumu anladım.

Aslında sınıf fonksiyonun adresini tutan bir değişken tanımlaması vardı. Ancak bu tanımlamayla oluşturlan değişkenle fonksiyonu çağırabilmek için tanımlanmış bir nesneyi kullanmam gerekiyordu. Mesela şu şekilde;
int main()
{
	TEXT text;
	(void) (TEXT::*f) (char) = &TEXT::Text;
	
	(text.*f)('a');
}

Burda asıl önemli husus şuymuş; bu şekilde çağrıldığı zaman Text fonksiyonuna birde gizli bir "this" ifadesi gönderiliyormuş. İşte kilit nokta buydu. This ifadesi oluşturulan sınıfın değişkenlerinin bulunduğu bölgenin başlangıç adresini taşıyor. Böylelikle hiçbir sıkıntı kalmadan fonksiyonu çağırabiliyoruz. Tam bu noktada "this" yapısının ne olduğu kafamda çok güzel oturdu.
Sonuç olarak şöyle pratik bir yol bularak bu işi kapattım. (Gerçi Text fonksiyonun gerçekten class içerisinde tanımlanması gereklimiydi onu bilemiyorum. Sanırım daha öncede bahsettiğim gibi benim önce sorunları nesne tabanlı olarak nasıl ele almam gerektiğini anlamam lazım)

TEXT *pf;

extern "C"
{
int fputc(int ch, FILE * f)
{
	pf->Text(ch);
	return 0;
}

}

........
.......

int main()
{
      TEXT text;
      pf = &text;
}


Umarım olayı anlatabilmişimdir. Eksiklerimi yanlışlarımı tamamlarsanız çok sevinirim.


mufitsozen

@gerbay, seninde cok iyi bildigin gibi c++ orneginde tanimlanan hali  ile hesapla, c'de ayni isimde olmaz. Arkadaslarin akli karismasin.

Ornek olarak bilen biri ok der ama, ... Name mangling??!!

biliyorum, sen ornegi cok derinlestirmek istemiyorsun ama, bence bu tip C++ nasil yapardiyi anlatmadan once Cdeki visibility rule'lari cok iyi anlamak gerekir.

Temel olarak erisebilirlik disinda aslinda struct ve class ayni concept, sana katiliyorum.

temel iki fark var:


  • standard (11.2.2):

        In absence of an access-specifier for a base class, public is assumed when the derived class is declared struct and private is assumed when the class is declared class.
  • (11.2):

        Member of a class defined with the keyword class are private by default. Members of a class defined with the keywords struct or union are public by default.
Aptalca bir soru yoktur ve hiç kimse soru sormayı bırakana kadar aptal olmaz.