Std::Vector<Object> İçinde Derived Object Kullanmak
-
Biliyorum çok sık soru sordum ama kusura bakmayın. Normalde ilk google'a sorarım ama bu sorunu nasıl arayacağımı bilemedim...
Bi tane vector var ve içinde Entity türünden nesneler var.
std::vector <Entity*> entities;
Bir tane de yine Entity'den türeyen Player sınıfı/nesnesi var.Player* player = new Player(renderer);
Add(player); // entities içine ekliyor
Bir döngü yardımıyla entities içindeki tüm nesneleri gezip hepsinin update methodunu çalıştırıyorum.for (size_t i = 0; i < entities.size(); i++) {
entities[i]->Update(_keyboardState, _gravity); // parametreler yukardan geliyor
}Normalde Player sınıfında Entity'nin Update methodunu override ettim, ama vector içine atınca Player'a Entity muamelesi yapıyor. Entity'nin Update methodunu çalıştırıyor.
Döngü içinde Player'a typeid yapınca Entity alıyorum.
Sebebi ne olabilir? -
Virtual Function ile tanış bakalım :)
-
virtual bildirimini unutmuyorsunuz değil mi? Aksi halde çalışacak metodu pointer seçer. Örnek:
#include <iostream>
#include <vector>
using namespace std;
class Entity
{
private: int _i;
private: string _name;
public: virtual void Update(int i)
{
_i = i;
}
public: virtual int GetI()
{
return _i;
}
public: virtual void Name(string name)
{
_name = name;
}
public: virtual string Name()
{
return _name;
}
};
class Player: public Entity
{
private: int _i;
private: string _name;
public: void Update(int i)
{
_i = i*2;
}
public: int GetI()
{
return _i;
}
public: void Name(string name)
{
_name = name;
}
public: string Name()
{
return _name;
}
};
int main() {
std::vector <Entity*> entities;
Player * a = new Player();
a->Name("Player a");
a->Update(4);
entities.push_back(a);
Entity * b = new Entity();
b->Name("Entity b");
b->Update(3);
entities.push_back(b);
for(int i = 0; i < entities.size(); ++i)
{
cout << "Once " << entities[i]->Name() << " " << entities[i]->GetI() << endl;
}
for(int i = 0; i < entities.size(); ++i)
{
entities[i]->Update(10);
}
for(int i = 0; i < entities.size(); ++i)
{
cout << "Sonra " << entities[i]->Name() << " " << entities[i]->GetI() << endl;
}
// your code goes here
return 0;
}
-
Bu gibi durumlarda (ortak metot sayısı azsa) interface'den kalıtım alın, aksi halde abstract bir sınıf oluşturup hepsini bundan türetin. Daha iyi bir alışkanlıktır (sonradan da genişletilebilir).
-
Teşekkürler ikinize de, dediğiniz gibi virtual olarak tanımlayınca sorun halloldu. Döngüde de ufak bir değişiklik yapmam gerekti:
for (std::vector<Entity*>::iterator i = entities.begin(); i != entities.end(); ++i)
(*i)->Update(_keyboardState, _gravity);
}
Interface işi çok uzatır da Entity'yi ya da ondan önce EntityBase falan diye bi sınıfı abstract yapabilirim. Ama şimdilik projede biraz yol almaya çalışacağım.Bu arada problemin adı slicing imiş:
http://stackoverflow.com/questions/274626/what-is-object-slicing
Tekrar teşekkürler.
-
Virtual methodu derived sınıfta tekrar yazdıktan sonra orjinal haline hala erişebilir miyiz?
C# taki base.helloWorld() gibi?
Çünkü methodun içini tekrar yazmak pek uygun bir yöntem gibi gelmedi. Böylece sadece eklemek istediklerimi yazarım kod fazlalığı olmaz dedim. -
İşte diyorum senin çözümün abstract sınıf:)
base'in elemanlarına (eğer erişim yetkisi varsa) miras alan sınıfta doğrudan base sınıfın isim uzayından erişilebilir. Örneğin Base::AMethod();
Örnek: http://ideone.com/pUEmeo
#include <iostream>
using namespace std;
class Base
{
public: virtual void BaseMethod()
{
cout << "Written by base." << endl;
}
};
class Delivered : public Base
{
public: void BaseMethod()
{
Base::BaseMethod();
cout << "Written by delivered." << endl;
}
};
int main() {
Base * base = new Base();
Base * delivered = new Delivered();
base->BaseMethod();
cout << endl;
delivered->BaseMethod();
// your code goes here
return 0;
}
-
Teşekkürler, tam da istediğim şey. Entity sınıfında bi kaç düzenleme ile yapabilirim sanırım.
Sormak istediğim birşey daha var.
Üstte bahsettiğim vector<Entity*> entities, EntityManager sınıfında bulunuyor.
Ben EntityManager'a GetPlayer() diye bir method yazmak istiyorum. Bu method entities içinden tipi Player olan nesneyi döndürecek. Bunun için entities'i bir döngüyle dolaşıp tek tek tiplerini kontrol etmek istedim. Ama yine yukarıda dediğim gibi typeid ile tipini alınca Entity olarak görüyor. Bu sorunu nasıl aşabilirim? Kafayı yemek üzereyim...
Player'ı entities içinden çıkarıp ayrı tanımlayarak bu sorunu aşabilirim ama bunun için de entities için yaptığım her şeyi player için de tek tek yapmam gerekiyor (update, render vs). Yapıcaksam biraz şık olsun derme çatma bi kod olmasın istiyorum. Var mı bir yolu?
*Bir çözüm daha geldi aklıma, entity içine isPlayer diye bir bool koyarım sonra onu kontrol ederim en olmadı. Caiz midir?
Waze tarafından 19/Kas/15 00:50 tarihinde düzenlenmiştir -
Waze bunu yazdı
Teşekkürler, tam da istediğim şey. Entity sınıfında bi kaç düzenleme ile yapabilirim sanırım.
Sormak istediğim birşey daha var.
Üstte bahsettiğim vector<Entity*> entities, EntityManager sınıfında bulunuyor.
Ben EntityManager'a GetPlayer() diye bir method yazmak istiyorum. Bu method entities içinden tipi Player olan nesneyi döndürecek. Bunun için entities'i bir döngüyle dolaşıp tek tek tiplerini kontrol etmek istedim. Ama yine yukarıda dediğim gibi typeid ile tipini alınca Entity olarak görüyor. Bu sorunu nasıl aşabilirim? Kafayı yemek üzereyim...
Player'ı entities içinden çıkarıp ayrı tanımlayarak bu sorunu aşabilirim ama bunun için de entities için yaptığım her şeyi player için de tek tek yapmam gerekiyor (update, render vs). Yapıcaksam biraz şık olsun derme çatma bi kod olmasın istiyorum. Var mı bir yolu?
*Bir çözüm daha geldi aklıma, entity içine isPlayer diye bir bool koyarım sonra onu kontrol ederim en olmadı. Caiz midir?
Normalde casting ile işi çözebilirsin hocam. Şuraya bi bak http://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast
Ürettiğin iki çözüm de pek caiz değil :) İlkinde kullandığın yapıyı bozuyorsun. İkincisinde sadece bir sınıf yüzünden bütün hepsine gereksiz bir fonksiyon ekleyeceksin.
Bu arada include işlemlerin karışacak muhtemelen. (Emin değilim) Eğer böyle birşeyle karşılaşırsan Forward declaration konusuna bakman gerekecek :)
-
NmC bunu yazdıWaze bunu yazdı
Teşekkürler, tam da istediğim şey. Entity sınıfında bi kaç düzenleme ile yapabilirim sanırım.
Sormak istediğim birşey daha var.
Üstte bahsettiğim vector<Entity*> entities, EntityManager sınıfında bulunuyor.
Ben EntityManager'a GetPlayer() diye bir method yazmak istiyorum. Bu method entities içinden tipi Player olan nesneyi döndürecek. Bunun için entities'i bir döngüyle dolaşıp tek tek tiplerini kontrol etmek istedim. Ama yine yukarıda dediğim gibi typeid ile tipini alınca Entity olarak görüyor. Bu sorunu nasıl aşabilirim? Kafayı yemek üzereyim...
Player'ı entities içinden çıkarıp ayrı tanımlayarak bu sorunu aşabilirim ama bunun için de entities için yaptığım her şeyi player için de tek tek yapmam gerekiyor (update, render vs). Yapıcaksam biraz şık olsun derme çatma bi kod olmasın istiyorum. Var mı bir yolu?
*Bir çözüm daha geldi aklıma, entity içine isPlayer diye bir bool koyarım sonra onu kontrol ederim en olmadı. Caiz midir?
Normalde casting ile işi çözebilirsin hocam. Şuraya bi bak http://stackoverflow.com/questions/28002/regular-cast-vs-static-cast-vs-dynamic-cast
Ürettiğin iki çözüm de pek caiz değil :) İlkinde kullandığın yapıyı bozuyorsun. İkincisinde sadece bir sınıf yüzünden bütün hepsine gereksiz bir fonksiyon ekleyeceksin.
Bu arada include işlemlerin karışacak muhtemelen. (Emin değilim) Eğer böyle birşeyle karşılaşırsan Forward declaration konusuna bakman gerekecek :)
casting ile ilk problem de çözülebilirdi aslında ama object oriented yazmanın bir anlamı kalmıyor o durumda.
-
NmC hocam sorunu dediğin gibi çözdüm. Öyle karışıklık falan da olmadı tek seferde çalışınca gözlerim yaşardı. :D Teşekkürler.
for (std::vector<Entity*>::iterator i = entities.begin(); i != entities.end(); ++i)
{
if (Player* player = dynamic_cast<Player*>((*i))) {
std::cout << "Player was here." << std::endl;
}
else {
std::cout << "Yet another entity." << std::endl;
}}
uLtRaLoVeR hocam daha akılcı bi çözüm varsa çok öğrenmek isterim.