PDA

Tam Sürümünü Görmek İçin : && ve || operatörlerini overload(aşırı yüklemek) etmek...


sckz
21/05/2005, 19:30
şimdi soru garip...
diyelim ki bir sınıfın şöyle bir üye fonksiyonu var..

friend bool operator && (const sinifim&, const sinifim&);

sinifim nesne1();
sinifim nesne2();

şimdi şöyle yaptığımda :
if (nesne1 && nesne2)
bu aslında şunun gibi bişi değil mi
if (operator &&(nesne1, nesne2))
yani bu aslında bir fonksiyon ve burda argümanlardan önce hangisine referans edileceği belli değil... (sonucta bu bi üye fonksiyon)

o zaman burdan şu sonuç çıkıyo... ben kendi tanımladığım tipler üzerinde mantıksal operatörleri kullanarak kısa-devre uygulayamam...
benim sorunum ise bunu nasıl gerçekleştirebilirim... ya da bu yolla ya da birbaşkası ile gerçekleştirebilir miyim?

neyine lasım derseniz... bende bilmiyorum... sadece kafama takıldı...


mr1yh1
21/05/2005, 19:59
fonksiyonlarda parametrelerin sırası önemli, hangi sınıfa ait oldukları o kadar değil (türeme durumları yüzünden)...

if (nesne1 && nesne2) ~ && ( nesne1,nesne2 )

deklarasyonda
operator &&(sinifim& ,sinifim&)

implementasyon kısmında :
operator &&( sinifim &s1, sinifim &s2)

yani sıra korunuyor..

mr1yh1
21/05/2005, 20:12
birde buraya yazdığım için özür dilerim
ama ben dünden bu yana konu açamıyorum ????

done yazıyor.. yeni konu yok :garip:

sckz
21/05/2005, 20:13
#include <iostream>
using namespace std;

int a()
{
cout << "a cagrildi" << endl;
return 1;
}

int b()
{
cout << "b cagrildi" << endl;
return 2;
}

int main()
{
cout << a() << b();
return 0;
}

gibi bir kod un çıktısı degisebilir..
örneğin ben vs 2003 te derledim aşağıdaki gibi bir sonuc aldım...

b cagrildi
a cagrildi
12

yani tamam parametrelerin sırası önemli fakat fonksiyona önce hangi argümanın aktarılacağı belli değil...

ve buna dayanarak kısa-devre olayını kendi tiplerim üzerinde uygulayamıyorum...

sckz
21/05/2005, 20:22
hatta ve hatta yukarıdaki koddan devam edersek
int i = a() + b();
burda da hangi fonksiyonun önce çağrılacağı belli değil.. yeah tabiki + operatörü önce a nın döndürdüğü değeri alıp sonra diğerinkiyle toplayacak fakat önce hangi fonksiyonun değer döndüreceği belli değil..
bu sorunu çözmesi kolay

int sabitle = a();
int i = sabitle + b();

deyince artık hangisinin önce çağrılacağını biliyoruz... fakat bunu dediğim olaya nasıl uygularız (ve diyelim ki burda sinifim için operator() da aşırı yükledik)....

sckz
21/05/2005, 20:24
demin kullandığım cout örneği yerine herhangi benim yazdığım fonksiyonu kullanığım da da böyle yani cout a özgü bişi değil...

mr1yh1
21/05/2005, 22:42
hatalı idi sildim:)...

mr1yh1
22/05/2005, 00:07
...

Sabahi
22/05/2005, 00:21
@sckz
Yukardaki programda "b cagrildi" cumlesinin ilk olarak yazilmis olmasinin nedeni b() fonksiyonun daha once deger donmesi degil. Sadece "<<" operatorunun bir ozelligi.
Program cout<<a()<<b(); ifadesini print edebilmesi icin once a() in dondugu sonrada b() nin dondugu degeri bilmesi gerek fakat hem a() hemde b() fonksiyonlarinin tanimlari "cout" ifadeleri icerdigi icin isler biraz karisiyor. Olayi kavramak icin bir stack dusun ve henuz ne yazacagimizi bilmedigimiz icin cout<<a()<<b(); ifadesini stack a push et. Ikinci olarak a() fonksiyonunda ki cout<<"a cagrildi"; ifadesini ve son olarak ta b() fonksiyonunda ki cout<<"b cagrildi"; iafadesini stack a push et. Stack a bir goz atarsak
cout<<"b cagrildi"; // top of the stack
cout<<"a cagrildi";
cout<<a()<<b(); // bottom of the stack
seklinde bir siralama goruruz ve bu noktada hem a() hemde b() nin dondugu degerlere sahip oldugumuz icin sira ile pop the stack ve print yapabiliriz. Ve sonuc aynen sizin programinizin veridigi ile esit olur.

mr1yh1
22/05/2005, 00:33
@ sabahi
cout lar çıkınca yine aynı,
şu kod da aynı sonucu veriyor..

#include <iostream>
using namespace std;

int first = 0;//ilk cagrilacak olanin degeri
int a()
{
if (first == 0 ) first = 1;
return 1;
}

int b()
{
if (first == 0 ) first = 2;
return 2;
}

int main()
{
cout << a() << b();

cout<<" first : "<<first;
return 0;
}

Sabahi
22/05/2005, 00:38
cout<<a()<<b(); yerine cout<<a()+b(); seklinde yaz. O zaman "<<" operatorunun farkini gormus olacaksin.

sckz
22/05/2005, 01:08
yukarıda zi aut u unutup başka bi fonksiyonda da benzer sonuç aldığımı söyledim sanırım..
yani :

#include <iostream>
using namespace std;


int a()
{
cout << "a cagrildi" << endl;
return 1;
}

int b()
{
cout << "b cagrildi" << endl;
return 2;
}

int c(int x, int y)
{
cout << "c cagrildi" << endl;
return x+y;
}

int main()
{
c(a(), b());
return 0;
}

bu kodun ciktisi platformdan platforma degisiyo (derleyiciden dolayı herhalde)
b cagrildi
a cagrildi
c cagrildi

şimdi benim sorunum şu eğer benim kullandığım operator && (.., ..) fonksiyonu da aynı şekilde çalışacaksa ben bu && operatöre kendi tiplerim üzerinde nasıl kısa-devre yaptırabilirim.. bu sorun || ve virgül , operatörünü aşırı yüklerken de var...
ve eğer ternary operatörü de aşırı yüklemeye izin verseydi aynı sorun ortaya cıkardı :

a() ? b() : c(); // a() b() ve c() nin dönen değeri int olsun

yukarıda a fonksiyonu kesin çalıştırılacak ve, ya b() ya da c() fonksiyonu çalıştırılacak.. ama eğer bunu int değil de kendi tipim için aşırı yükleme iznim olsaydı... yazacağım ifade gerçekte bir fonksiyon olacağı için hem a() hem b() hem de c() cağrılacaktı... // burda a() dan dönen değer kendi tiipim olmalı tabi ki

derdimi anlatabildim sanırım..

myavuzselim
22/05/2005, 03:21
Niye && || ... operatorlerini manipule etmek istiyorsun? Bildigim kadariyla sinifinin nesnelerine bool anlami verdirebiliyorsun.
#include <iostream>

using namespace std;

class Test {

public:
Test(bool b_) : b(b_) {}

operator bool() const {
return b;
}

private:
bool b;

};

int main() {
Test t(true), f(false);

cout << (t && f) << endl;
cout << (t || f) << endl;
cout << !t << endl;

return 0;
}

sckz
22/05/2005, 03:25
that's it

mr1yh1
22/05/2005, 06:58
int main()
{
c(a(), b());
return 0;
}

bu kodun ciktisi platformdan platforma degisiyo (derleyiciden dolayı herhalde)
bu durum, sadece a() ve b() nin çağırılma sırası sonucu etkiliyorsa bir problem...

cout << a() << b() problem yarattı çünkü ekranda önce hangisini gördüğümüz önemli idi..
önce a() nın çağırılması b() yi etkiledi .. b() yazıyı bir alt satıra basmak zorunda kaldı..

Test sınıfının bool() cast ile yaptığı stil ile ilgili (sentetik şeker) ...
çağrılma sırasına bağımlılık olduğunda yaşanacabilecek problemi çözmüyor...


#include <iostream>

using namespace std;

class Test {
public:
static int count;
Test(bool b_) : b(b_) {;}

operator bool() const { count++ ; return b && ( count%2 ) ; }

private:
bool b;
};

int Test::count = 0;

int main() {
Test t(true), f(false) ;
cout << (t || f) << endl;//sonuc 1
Test::count = 0 ;//basa donduk..
cout << (f || t) << endl;//sonuc 0
return 0;
}

Sabahi
22/05/2005, 10:00
yukarıda zi aut u unutup başka bi fonksiyonda da benzer sonuç aldığımı söyledim sanırım..
yani :



Evet soyledin ama sadece fonksiyonlarin icindekileri degistirdin ki bi manasi yok. Asil onemli olan main icerisindeki cout ifadesi eger onu cout<<a()+b(); seklinde degistirmis olsaydin "<<" operatoru ile aritmetik operatorlerin arasindaki farki gorurdun.

mr1yh1
22/05/2005, 12:42
problemin derleyicilerin farklılığından kaynaklanmadığını görüyorum şimdi.
Bu klasik bir programlama yanlışından kaynaklanıyor.
( side-effect)
ilgili kural da şu idi:
Bir ifade, ya fonksiyondur ve sadece değer döndürürmelidir , ya da prosedür dür kesinlikle değer döndürmemelidir..

sckz
22/05/2005, 14:30
Test sınıfının bool() cast ile yaptığı stil ile ilgili (sentetik şeker) ...
çağrılma sırasına bağımlılık olduğunda yaşanacabilecek problemi çözmüyor...

bunu pek anlamış değilim.. problemi çok güzel çözmüyormu.. çünkü burda kullanılan && ya da || operatörü gerçekten bir operatör gibi davranıyor.. yani bir fonksiyon değil. benim asıl sorunum da buydu zaten..
diğerlerini annatmamın nedeni.. kullandığım bir fonksiyon olduğu için ve argümanlarını kafasına göre kullandığını göstermek içindi.. ve ben bu yüsden kendi tiplerim e mantıksal operatörlerle kullanırken kısa-devre olayını sağlayamıyodum... ama dönüşüm operatörü kullanarak bunun altından kalkabildim...
şuan BeOS ta sorun olduğu için onda deneyemiyorum.. ama linux kullanan bir arkadaş denesin.. bu muhtemelen kullanılan derleyiciye göre değişen bişi.. fonksiyonların argümanlarının düzensiz birşekilde aktarıldığını bir kitapta okudum (sanırım Robert Lafore un nesne yönelimli programlama kılavuzu ya da more exceptional c++ ya da c++ gotchas.. tam hatırlamıyorum)

mr1yh1
22/05/2005, 15:01
dün bütün günümü bunu düşünmek aldı desem, çok abartmış olamam :)
ilk önce && operatorunu aşırı yüklemeye çalıştık..
daha sonra bool cast ı aşırı yükledik..

1.yöntem :aşırı yüklü && i &&& ile göstericem:
a&&&b&&&c --> &&& ( (a &&& b) &&& c ) --> hangisi önce değer döndürecek , a&&&b mi yoksa c mi...sen diyorsun ki değişiyor.
O zaman , herhangi birinin daha önce değer döndürmesinin işlemin sounucu etkilemeyeceğinde emin olmamız lazım..

2.yöntem : aşırı yüklenmiş bool cast'ı mybool olarak adlandırırsam:

my_bool(a)&&my_bool(b)&&my_bool(c)--->
&&( ( my_bool(a) && my_bool(b) ) && my_bool(c) )
--> görüyorsun ki sorun devam ediyor..
my_bool(a)&&my_bool(b) mı önce döner my_bool(b) mi

myss çözümünde, bool() castı const olarak kullanarak my_bool() un nesneyi değiştirmesini engellemiş..( yani ilk örnekde fonsiyon değil, sabit kullanmak gibi , o zaman yan etki de imkansız )
fakat bu kısıtlama benim örneğimdeki statik üyeyi bağlamadı ,
ama daha önemlisi çevre değişkenlerini hiç bağlamaz..

sckz
22/05/2005, 16:20
evet orda hangisinin önce değer döndüreceği belli değil.. sadece dönen değerlerden hangisinin önce kullanılacağı belli...

#include <iostream>
#include <string>
using namespace std;

class MyClass
{
private :
int i_;
string ismim_;
public :
MyClass(int i=0, string ismim = "Unnamed") : i_(i), ismim_(ismim) {}
MyClass operator()();
friend bool operator && (const MyClass &, const MyClass &);
};

MyClass MyClass::operator()()
{
cout << ismim_ << endl;
return *this;
}

bool operator && (const MyClass & mc1, const MyClass & mc2)
{
return mc1.i_ && mc2.i_;
}

int main()
{
MyClass m1(0, "birinci");
MyClass m2(3, "ikinci");

if (m1() && m2())
{
cout << "if in içindeyim" << endl;
}
return 0;
}

bu kodun ciktisi :
ikinci
birinci

gördüğün gibi kısa-devre yok..

şimdi okumaya devam :

#include <iostream>
#include <string>
using namespace std;

class MyClass
{
private :
int i_;
string ismim_;
public :
MyClass(int i=0, string ismim = "Unnamed") : i_(i), ismim_(ismim) {}
MyClass operator()();
operator bool() const
{
return i_ != 0;
}
};

MyClass MyClass::operator()()
{
cout << ismim_ << endl;
return *this;
}

int main()
{
MyClass m1(0, "birinci");
MyClass m2(3, "ikinci");

if (m1() && m2())
{
cout << "if in içindeyim" << endl;
}
return 0;
}

bu kodun ciktisi sadece:
birinci

şimdi kısa-devre olayını hallettim..
bide &&& operatörü ne işe yarıyo... buna daha önce pek rastlamadım..

mr1yh1
22/05/2005, 18:25
&&& operatörü ne işe yarıyo... buna daha önce pek rastlamadım..

çünkü &&& operatörünü ben uydurdum :)
yani bizim aşırı yüklediğimiz && ile normal && yi görsel olarak daha ayırmak için öyle yazdım..

evet orda hangisinin önce değer döndüreceği belli değil.. sadece dönen değerlerden hangisinin önce kullanılacağı belli...
evet doğru
ama && zaten sıra önemsiz bir operatör
ve o özelliği korunarak aşırı yüklenmeli
( bütün operatörler için mümkünse bu tavsi ediliyor ve senin kodun bunu sağlıyor)

senin m1() m2() ise,
hem bir prosedür ( cout u değiştiriyor ) ,
hem de bool döndüren masum bir foksiyon gibi davranıyor.
Fakat :
m1() && m2() ( != özdeş değil) m2() && m1()
şimdi, sence önce hangisinin işleneceği önemli değil mi ?
m1() ilk çağırılırsa farklı bir cout bulacak, ikinci çağrılırsa farklı..

mesela m1() ve m2() şu önermeyi döndürse idi :
" ekrana ilk m1() yazdı" ...
senin if ( m1() && m2() ) ifadesi ;
ilk m1 çağrılırsa doğru , çağrılmazsa yanlış olurdu..

senin kodu derledim benim makinada,
sağdan sola yapıyor operator()() çağrısını..
başka derleyiciler için farklı ise yine başa döneriz..
&&( m1() , m2() ) durumu..

sckz
22/05/2005, 18:38
dikkat burda () operatörünü MyClass döndür diye ayarladım... yani o bir MyClass türünde bi nesne döndürüyo.. sonra dönen nesne MyClass olduğu için sınıf içinde tanımlı operator && buluyo.. ve bunu kullanıyo... yani bu bool bir değer döndürmüyo...

aslında tam olarak ne demek istediğini yine annamadım..
m1() && m2() şeklinde yasdığımızda eğer operator&& üye fonksiyonunu kullanıyosak... hangisinin önce işleneceği önemli tabi ki fakat bu değişiyo... (bir fonksiyon olduğu için)

ama dönüşüm operatöründe böle bişi yok.. m1() önce cagrılıyo... sonra üyesi olduğu nesneyi bırakıyo... sonra derleyici o nesne içindeki dönüşüm operatörünü bulup onu bool değere çeviriyo.. değerin false olduğunu gören && operatörü ikinci yi ( yani m2() yi) hiç incelemeden false döndürüyo...

mr1yh1
22/05/2005, 19:17
ama dönüşüm operatöründe böle bişi yok.. m1() önce cagrılıyo... sonra üyesi olduğu nesneyi bırakıyo... sonra derleyici o nesne içindeki dönüşüm operatörünü bulup onu bool değere çeviriyo.. değerin false olduğunu gören && operatörü ikinci yi ( yani m2() yi) hiç incelemeden false döndürüyo...
o kadar emin olma :)

bu kodun ciktisi :
ikinci
birinci

gördüğün gibi kısa-devre yok..
önce m2() çağrılmış...
hatta bir de m3() ekle sağ tarafa ,önce o çağrılıyor..

sckz
22/05/2005, 19:22
hayır senin verdiğin çıktı... operator && üyesini kullanınca... dönüşüm operatörünü kullanınca aşağıdaki gibi :

birinci

yazıyo

mr1yh1
22/05/2005, 22:57
hayır senin verdiğin çıktı... operator && üyesini kullanınca... dönüşüm operatörünü kullanınca aşağıdaki gibi :

birinci

yazıyo
evet haklısın , ikincideki && tıpkı ANDTHEN gibi sıra önemli işliyor.. lazy C++ olmuş :garip:
&& ve || in built-in halleri için o side-effect tehlikesi de kalmıyor ..

sckz
23/05/2005, 06:04
zaten bu operatör aşırı yükleme olayı bazen kafa karıştırıcı olabiliyor... bu yüsden herhalde c# a koymamışlar... ama bence çok da keyifli.. böyle üzerinde uzun uzun zohbetler dönüyor... beni şaşırtan birdiğer operatör -> olmuştur... normalde önceden tanımlı -> operatörü ikilidir. fakat aşırı yüklenen -> operatörü tekli... bunun üzerinde çalıştığım gün zi plas plas a ne kadar aşık olduğumu bir kes daha hatırladım... (birde bişi daha, daha önceki konulardan birinde bir arkadaşımız bir yazısının bir kısmının bir cümlesinde ""if loop"" diye bişiden bahsetmiş.. bunun ne olduğunu bilen varmı... cahilliğime verin böle bişi yi ilk defa duyuyorum... ve biras saçma geldi.. ve birşey daha "bir" kelimesini amma çok kullandığımın farkındayım)

mr1yh1
23/05/2005, 14:36
if loop dan kasıt herhalde şu:

int x ;
label1: x++;
if ( x<10 ) goto label1;

öğrenildikten sonra unutulması zorunlu bişi bence..

acehreli
23/05/2005, 23:37
Bu guzel sohbeti kacirdigima uzuldum.

Evet, bizim tanimladigimiz operator&& (ve ||) kisa devre yapamaz. Bunun nedeni bir islev olmasidir. Bunun nedeni, islevler cagrilmadan once butun parametrelerinin sonuclanmasi geregidir.

Yine evet, islev parametrelerinin hangi sirada isletildikleri belirsizdir. Her derleyici istedigi sirada yapabilir.

Sabahi, senin anlattigin yontem ancak bir gerceklemenin sectigi yontem olabilir. c(a(),b()) isleminde a() ve b()'nin gcc'de ve VC++'ta ayri siralarda isletildiklerini biliyoruz.

Ali

sckz
24/05/2005, 04:55
ali hocam sohbet devam ediyor...
şimdi işin güsel tarafı aslında burda kısa-devre olayında myss kardeşimin düşüncesi benim başka işlerimde de yaradı...

olaydan kısaca bahsedersem...

örneğin:

int armut[10];
armut[0] = 11; // armut[0], *(armut + 0) a cevrilecek....
armut[1] = 22; // armut[1], *(armut + 1) e cevrilecek...
armut[-2] = 33; // armut[-2] ---->> *(armut + (- 2))...

// madem toplamanın degisme öselliği var :

(-2)[armut] = 44; // ---->> *(-2 + armut) olacak

işte bunu kendi tiplerim e nasıl uygulayacağım sorundu... yannız myss arkadaşım bana c++ dönüşüm operatörü olduğunu hatırlattı...

ve şimdi sorunum çözüldü :

#include <iostream>
#include <vector>
using namespace std;

template <typename T, size_t boyut>
class Gonul
{
public :
Gonul()
{
dizi_.reserve(boyut);
}
operator T*()
{
return &dizi_[0];
}

private :
vector<T> dizi_;
};
int main()
{
Gonul<int, 10> obj;
0[obj] = 11;
obj[1] = 22;
(-2)[obj] = 33;
cout << obj[0] << " " << obj[1] << " " << (-2)[obj];

return 0;
}

mr1yh1
24/05/2005, 15:35
bu yazım şekilini ilk defa görüyorum, çok ilginç ...
mingW derledi ve doğru bir şekilde çalıştırdı ..
ama VC++ ( 2005 express beta ) debug açıkken hata verdi..
vektörün , bellekten ayrılmış
ama initialize edilmemiş ( vektör içersinde )
kısmına ulaşmaya izin vermiyor..
( atamalardan sonra hala data_.size()= sıfır .. )

sckz
24/05/2005, 17:26
vc++ evet debug açıkken hata verir.. çünkü &dizi_[0] - 2 adresi benim için ayrılmamış.. ben bana ayrılmadığı halde.. yapmak istediğim şeyi gösterebilmek için oraya saldırdım..

size() ın sifir göstermesi... vektör için [] operatörünü kullanarak atama yaptığımızda olayın push_bak gibi işlememesinden kaynaklanıyo...

örneğin :
vector<int> gonul;
gonul.reserve(10); // gerek yok ama zevk ossun
gonul[0] = 11;
gonul[1] = 22;
gonul[2] = 33;

cout << gonul.size(); // ekrana yine 0 yazılacak

bu kodun ciktisi da sıfır oluyo... bu vektörlerin ilgili [] operatörünü aslında bu şekilde kullanım için yapılmadıklarının bir göstergesi olabilir.. hatta burda [] operatörü ayrılmış belleği bile inişılız yapmıo... demekki vektörleri böle kullanmak herzaman için hoş karşılanan bir tutum değil..

aşağıdaki kullanım ama tamamıyla doğru...

int gonul[10];
int* ptrGonul = &gonul[5];
(-2)[ptrGonul] = 15;