Selamün Aleyküm, hayırlı bayramlar;
Allah kurbanlarınızı kabul eylesin.
Bir önceki açtığım konumda sınıfların varsayılan olarak stack'de mi yoksa heap'de mi oluşturulması gerektiğini sormuştum. C++ harici çoğu dilin sınıfları stack'de değil de heap alanında oluşturmasının sebebinin slicing (dilimleme) sorununu ortadan kaldırmak olduğunu zannediyorum.
Bu sorunu C++ dilinde denemek için şu örneği hazırladım:
#include <iostream>
using namespace std;
class Database
{
protected:
std::string db;
public:
Database(const std::string& db) : db(db)
{
}
virtual void display()
{
cout << "Database:" << endl
<< " - Database Name: " << db << endl;
}
};
class PostgreSQL : public Database
{
private:
int db_version;
public:
PostgreSQL(const std::string& db, int db_version)
: Database(db), db_version(db_version)
{
}
void display() override
{
cout << "PostgreSQL:" << endl
<< " - Database Name: " << db << endl
<< " - Database Version: " << db_version << endl;
}
};
class MongoDB : public Database
{
private:
int db_version;
public:
MongoDB(const std::string& db, int db_version)
: Database(db), db_version(db_version)
{
}
void display() override
{
cout << "MongoDB:" << endl
<< " - Database Name: " << db << endl
<< " - Database Version: " << db_version << endl;
}
};
void display(Database db /* Database& db */)
{
db.display();
}
int main()
{
PostgreSQL postgresql("PostgreSQL Example", 1);
MongoDB mongodb("MongoDB Example", 2);
display(postgresql);
display(mongodb);
return 0;
}
Bu örneği derleyip çalıştırdığımda şu çıktıyı elde ettim:
Database:
1. Database Name: PostgreSQL Example
Database:
1. Database Name: MongoDB Example
Normalde elde etmeye çalıştığımız çıktı şöyle olmalı:
PostgreSQL:
1. Database Name: PostgreSQL Example
2. Database Version: 1
MongoDB:
1. Database Name: MongoDB Example
2. Database Version: 2
İşte burada dilimleme - slicing sorunu ortaya çıkıyor. C++'da bunu yapmanın birkaç yolu var:
1- display fonksiyon parametresini referans olarak tanımlama:
void display(Database& db)
{
db.display();
}
Fakat burada bir sorun daha ortaya çıkıyor ki o da geçici bir nesneyi argüman yapamıyoruz:
MongoDB mdb ("aaa", 1);
display(mdb); // TAMAM, Çalışıyor
display(MongoDB("aaa", 1)); // HATA, Derlenme hatası
2- display fonksiyon parametresini işaretçi yapmak:
void display(Database* db);
Lakin yine geçici bir nesneyi argüman olarak atayamıyoruz:
display(MongoDB("aaa", 1)); // HATA, Derleme hatası
3- Nesneyi statik değil, dinamik olarak oluşturmak (Heap Alanında):
void display(Database* db);
MongoDB* mdb = new MongoDB("aaa", 1);
display(mdb); // TAMAM, Çalışıyor.
Ama bunun da bellekten silinmesi gerekir ve çoğu zaman zahmetli. Ayrıca boyutları küçük olacak olan sınıf nesnelerini stack'de oluşturmak bence daha iyi.
Şimdi bu 3 yöntem de benim istediğim şey değil. Ben ise hem stack'de oluşan nesneyi kullanmak istiyorum:
MongoDB mdb("aaa", 1);
Hem geçici nesneyi kullanmak istiyorum:
display(MongoDB("aaa", 1));
Hem de işaretçi ve dinamik bellek yöntemini kullanmak istemiyorum.
Hem de bu kalıtım yöntemini bozmak istemiyorum :).
Bunun için nasıl bir yöntem izlemeliyim? display fonksiyonunda gönderilen argümanın türünün ne olduğuna bakarak birşeyler yapabilir miyim? Ya da ben imkansız olan bir şeyi mi istiyorum? :)
Teşekkürler!
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]