Yapıcılar ve yıkıcılar objemizin oluşturulma ve yok edilme aşamalarında çalışan fonksiyonlarımızdır.
Constructors
Şimdi geçen dersimizdeki koda bakalım:
#include <iostream>
using namespace std;
class Vector{
public:
int x, y, z;
void deger_ata(int xx, int yy, int zz) {
x = xx;
y = yy;
z = zz;
}
void print(){
cout << x << ", " << y << ", " << z << "\n";
}
Vector topla(Vector vec2) {
Vector toplam;
toplam.x = x + vec2.x; // vec1.x + vec2.x;
toplam.y = y + vec2.y; // vec1.y + vec2.y;
toplam.z = z + vec2.z; // vec1.z + vec2.z;
return toplam;
}
};
int main() {
// Vektörleri tanımladık
Vector vector1; // Vektör 1
Vector vector2; // Vektör 2
Vector vector3; // Vektör 1 ve 2 nin toplamı
vector1.deger_ata(3, 4, 5);
vector2.deger_ata(7, 8, 0);
// Vektörleri topladık
vector3 = vector1.topla(vector2);
// Vektörleri yazdırdık
vector1.print();
vector2.print();
vector3.print();
}
// 3, 4, 5
// 7, 8, 0
// 10, 12, 5Vector::deger_ata(…) fonksiyonu yardımıyla sınıfımızdaki değişkenlere değer atıyoruz. Bunu yapmak için öncelikle Vector vec1; gibi bir değişken oluşturuyoruz. Daha sonra vec1.deger_ata(…) şeklinde fonksiyon çağrısı yaparak değer atama işlemini gerçekleştirebiliyoruz. Her şey iyi güzel fakat bunun tıpkı primitive değişkenlerdeki gibi int sayi = 5; şeklinde bir yolu yok mu. Bu tip bir kullanım için yapıcı metodlarımız var.
Yapıcı fonksiyonlar (Constructors)
- Normal fonksiyonlar gibidir.
- Objenin oluşturulmasıyla beraber çalışır.
- Birden fazla olabilir.
- Eğer sınıf için hiçbir constructor yazılmamışsa compiler tarafından default constructor oluşturulur.
- Eğer herhangibir constructor yazılırsa, default constructor oluşturulmaz. Bu sebepten eğer ihtiyacımız varsa bizim default constructor yazmamız gerekir.
- Return type yoktur. Yani bir şey döndürmez.
- Sınıfın adıyla aynı isme sahip olur.
- Çağrılabilmesi için public: altında olmalıdır ama private veya protected altında da olabilir (bunları sonraki derste göreceğiz)
Şimdi Vector sınıfımız için bir constructor yazalım :
class Vector {
public:
int x, y, z;
Vector(int xx, int yy, int zz) {
x = xx;
y = yy;
z = zz;
}
...Tabi bir tane constructor yazdığımız için default constructor’ımız silindi. Onu da yazalım:
class Vector {
public:
int x, y, z;
Vector(int xx, int yy, int zz) {
x = xx;
y = yy;
z = zz;
}
Vector() {
}
...Eğer default constructor’ımızı yazmasaydık Vector vec1; gibi bir ifade kullanamazdık; hata alırdık.
Şimdi nasıl kullanıldığına bakalım:
int main() {
// Vektörleri tanımladık
Vector vector1(3, 4, 5); // Vector(int xx, int yy, int zz)
Vector vector2{ 7, 8, 0 }; // Vector(int xx, int yy, int zz)
Vector vector3; // default constructor Vector()Tüm kodumuz:
#include <iostream>
using namespace std;
class Vector {
public:
int x, y, z;
Vector(int xx, int yy, int zz) {
x = xx;
y = yy;
z = zz;
}
Vector() {
}
void print() {
cout << x << ", " << y << ", " << z << "\n";
}
Vector topla(Vector vec2) {
Vector toplam;
toplam.x = x + vec2.x; // vec1.x + vec2.x;
toplam.y = y + vec2.y; // vec1.y + vec2.y;
toplam.z = z + vec2.z; // vec1.z + vec2.z;
return toplam;
}
};
int main() {
// Vektörleri tanımladık
Vector vector1(3, 4, 5); // Vector(int xx, int yy, int zz)
Vector vector2{ 7, 8, 0 }; // Vector(int xx, int yy, int zz)
Vector vector3; // default constructor Vector()
// Vektörleri topladık
vector3 = vector1.topla(vector2);
// Vektörleri yazdırdık
vector1.print();
vector2.print();
vector3.print();
}
// 3, 4, 5
// 7, 8, 0
// 10, 12, 5this keyword
Constructor’ımıza bir daha bakalım:
Vector(int xx, int yy, int zz) {
x = xx;
y = yy;
z = zz;
}Bunu şu şekilde de yazabilirdik:
Vector(int x, int y, int z) {
x = x;
y = y;
z = z;
}Burada bir kafa karışıklığı söz konusu. Hangi x sınıfa ait, hangi x dışardan geliyor. Buradaki tüm değişkenler dışarıdan parametre yolu ile geliyor YANİ yanlış bir kullanım yaptık.
Sınıfımıza ait x i belirtmek için bu->x dememiz lazım. Yani bu sınıfa ait x değişkeni. Tabi ki yazılım dili İngilizce olduğu için this->x diye yazıyoruz:
Vector(int x, int y, int z) {
this->x = x;
this->y = y;
this->z = z;
}Dikkatli gözler bu keyword’ün aslında objemizi işaret eden bir pointer olduğunu farkedecektir.
member initializer list
Yukarıdaki yapıcı fonksiyonların bu şekilde de yazabilirdik:
Vector(int xx, int yy, int zz) : x{ xx }, y{ yy }, z{ zz } {
}
Vector() : x{}, y{}, z{} {
}
// this-> kullanmıyoruz:
// Vector(int x, int y, int z) : x{ x }, y{ y }, z{ z } {}
Destructors
Yapanlar var da yıkanlar olmaz mı? Şükürler olsun ki gerçek hayattaki kadar fazla yıkıcımız yok.
- Her sınıfın bir tane yıkıcı fonksiyonu olur.
Neden 2 değil 3 değil de 1? Çünkü, obje geçerlilik alanı bittikten sonra ölür. Yani bir constructor çağrısındaki gibi bizim vec1(3,4,5); gibi bir çağrımız söz konusu değil. Bu sebepten ötürü eğer yıkıcı fonksiyonlar birden fazla olursa compiler hangi yıkıcı fonksiyonu çağıracağını bilemez. Zaten genelde gerek de yoktur.
- ~SınıfAdı(){} şeklinde yazılır. Baştaki işaretin adı tilda~
Peki bizim böyle bir şeye neden ihtiyacımız var?
Sıfımızdaki değişkenler otomatik olarak yok olacaktır. Fakat dynamic memory allocation (new) ile bir bellek ayırdıysak bu ayrılan belleği yok etmek için kullanıyoruz. Bu memory leakleri önlüyor.
#include <iostream>
using namespace std;
class MyClass {
public:
int* a_huge_data;
MyClass() {
a_huge_data = new int[1'000'000];
cout << "constructor" << endl;
}
~MyClass() { // Destructors
delete[] a_huge_data;
cout << "destructor" << endl;
}
};
int main() {
MyClass a, b, c;
}
Tabi farklı amaçlarla da kullanılabilir.
Bakınız
- RAII nedir?
- Object Lifetime in C++
- member initializer list ‘in normal atamaya (=) göre farkı nedir?


Leave a Reply