Wywołanie konstruktora a dziedziczenie

0

Mam dwie klasy

class Character

oraz

class Player : public Character

w Player mialem jeden konstruktor (tylko jeden)

Player::Player(const std::string& name, const std::string& avatarPath) :
Character(name, avatarPath)
{
} 

ale teraz potrzebuje zrobic drugi. Moze nie tyle co drugi co potrzebuje usunac name z pierwszego (drugi nie musi istniec)
wiec zrobilem

Player::Player(const std::string& avatarPath)
{
	
} 

no i pokazuje, ze Character nie ma domyslnego konstruktora (no bo ma tylko jeden zdefiniowany). Co oryginalnie chcialem zrobic to cos takiego

Player::Player(const std::string& avatarPath)
{
	std::string name = GetNameFromFile();
	this->Player(name, avatarPath);
}  

no ale to nie zadziala (bo nie ma konstruktora domyslnego w character) wiec pierwsza mysl rozwiazania jest taka by zdefiniowac go i zrobic pustym.

PYTANIE. Czy jest ok, ze wywolaja sie dwa konstruktory klasy bazowej podczas tworzenia obiektu? Wydaje mi sie, ze tak, ale chcialem sie upewnic, a nie moglem nic znalezc w googlach

0

juz widze ze to rozwiazanie nie jest ok bo nie inicjalizuje odpowiednio zmiennych w character mimo ze oba konstruktory tam sa wywolane.

1

A nie możesz wywołać konstruktora Character z atrapą (pustym stringiem) w miejscu name, a potem w konstruktorze Player ustawić już pobraną wartość?

1

jeśli dobrze zrozumiałem, że klasa bazowa koniecznie musi zawierać konstruktor Character(const std::string& name, const std::string& avatarPath), a domyślnie, jeżeli name nie jest podawany chcesz w konstruktorze pobierać z pliku to może dodaj prostą funkcję setName w klasie bazowej, ew. udostępnij tę zmienną składową i do niej przypisz rezultat tej funkcji? Taki szybki przykład:

class Character
{
public:
	Character(const std::string& name, const std::string& avatarPath) :
		mName{name},
		mAvararPath{avatarPath}
	{

	}

	void setName(const std::string& name)
	{
		mName = name;
	}

private:
	std::string mName;
	std::string mAvararPath;
};

class Player : public Character
{
public:
	Player(const std::string& name, const std::string& avatarPath) :
		Character{name, avatarPath}
	{

	}

	Player(const std::string& avatarPath) :
		Player{"", avatarPath}
	{
		setName(getNameFromFile());
	}

	std::string getNameFromFile() const
	{
		return "name";
	}
};
0

Jawne odpalanie konstruktora wydaje mi się słabym pomysłem. Wydaje się, że powinieneś tam ustawiać po prostu pole name
Co do wywołania bazowego konstruktora, możesz zawsze wywołać ten jedyny z pustym stringiem.
Hmm możesz też chyba zrobić konstruktor chroniony (protected), który nie przyjmuje name na parametrze. Wtedy klasa Character wymaga podania nazwy, ale nie dotyczy to klas dziedziczących.

0

rozwiazalem to tak jak @twonek napisal.

Konstruktor nie musial miec tych parametrow, ale po prostu zastanawialem sie czemu tak nie zadziala...

class Character : public GameObject
{
	public:
	Character(const std::string& cAvatarPath)  : cAvatarPath(avatarPath), mHitpoints(100), mAvatarWidth(359), mAvatarHeight(323)
	{
		mTargetRect.w = GetWidth();
		mTargetRect.h = GetHeight();
		mHpBar.h = cHealthBar;
		mName = "deafult";
	}
}

no i player

class Player : public Character
{
public:
	Player(const std::string& avatarPath):
	Character(avatarPath)
	{
		mName = LoadPlayerName();
	} 
}

dziala. Jednak nadal mnie nurtuje czemu nie stworzyl sie odpowiednio obiekt?

2

A nie jest tak, że tworzysz nowy obiekt tym wywołaniem konstruktora? Czyli nie zmieniają się pola obiektu w którym wywołujesz, tylko tworzysz zupełnie nowy, ale nie zapisujesz do żadnej zmiennej więc idzie to w p*du.

0

bylo robione mniej wiecej cos takiego
http://ideone.com/vA48ZE

2

@fasadin ale niby jak ma to działać? Wg standardu delegowanie konstruktora działa tylko w liście inicjalizacyjnej i tyle.
http://www.learncpp.com/cpp-tutorial/b-5-delegating-constructors/

Poza tym popatrz na kolejność inicjalizacji klas, podklas itd.

0

myslalem ze mozna delegowac w ramach tej samej klasy poza lista inicjalizacyjna. Ale widocznie nie mozna ;)

0

@fasadin jakbyś zrobił tak:

class Bar: public Foo
{
public:
	Bar(int var):Foo(var){}
	Bar() : Bar(4)
	{	}

};

to powinno iść. Gorzej jak, ta liczba miała być wyliczana w ciele konstruktora delegującego, to wtedy tylko static inline Ci zostało ;)

EDIT: jak oddelegujesz w ciele to stworzysz tymczasowy obiekt na stosie który poleci w diabły po wyjściu ze scope'a.

0

wlasnie problem polegal na tym ze ta wartosc jest wyliczana.
wole zmienic architekture niz uzywac static inline ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1