• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed Projektowanie klasy abstrakcyjnej, problem z wirtualnym przciążaniem operatora<<

VPS Starter Arubacloud
+1 głos
316 wizyt
pytanie zadane 3 czerwca 2018 w C i C++ przez Jakub 0 Pasjonat (23,120 p.)
zamknięte 3 czerwca 2018 przez Jakub 0

Hej, ćwicząc nowo nabywaną wiedzę zacząłem projektować prostą klasę bazową o nazwie BaseRectangle, z niej dziedziczy klasa opisująca kwadrat oraz opisująca prostokąt. Dla klas potomnych chciałem przeciążyć operator<<

( jego definicja wygląda inaczej dla dwóch klas dziedziczących ), problem jest jednak taki że podany operator nie powinna przeciążać metoda lecz zwykła funkcja z pierwszy argumentem jako referencja na obiekt klasy std::ostream a z drugim jako np. stała referencja na nasz obiekt. Wobec tego funkcja operatora<< wywołuje odpowiednią metodę wirtualną ( przeciążającą << ) w zależności od podanego w argumencie obiektu dziedziczącego po BaseRectangle. Wszystko wygląda tak:

#include <iostream>
#include <string>

class BaseRectangle;
std::ostream& operator<<(std::ostream&, const BaseRectangle&); //drugi parametr to 
//referencja typu klasy abstrakcyjnej

///---------------------------------------------------------------------------------------

class BaseRectangle { //klasa abstrakcyjna
	friend std::ostream& operator<<(std::ostream&, const BaseRectangle&);
public:
	struct Coords { int x; int y; };
private:
	Coords pos;
public:

	BaseRectangle(int pos_x=0, int pos_y=0) : pos{ pos_x,pos_y } {}

	Coords& returnPos() {
		return pos;
	}

	Coords returnPos() const {
		return pos;
	}

	void move(int x, int y) {
		pos = { x,y };
	}

	virtual long area() = 0;

protected:
	virtual std::ostream& operator<<(std::ostream& os) const = 0; //by klasy potomne wiedzialy o istnieniu tej metody i mogły mieć jej 
//własną definicje ale by reszta programu nie miała do tej metody dostępu 

};

///---------------------------------------------------------------------------------------

class Rectangle : public BaseRectangle { //prostokąt 

	friend std::ostream& operator<<(std::ostream&, const BaseRectangle&);

	virtual std::ostream& operator<<(std::ostream& os) const { //prywatna sekcja by nie moc stosować zapisu w stylu: 
//Rectangle << cout; ( z tej metody korzysta funkcja zaprzyjaźniona )
		os << "width = " << width << ", height = " << height << std::endl;
		os << "pos(x,y) = ( " << returnPos().x << ", " << returnPos().y << " )\n";
		return os;
	}

private:
	int width;
	int height;
public:
	Rectangle(int w=0, int h=0, int x=0, int y=0) : BaseRectangle(x,y), width(w), height(h) {}

	virtual long area() {
		return width*height;
	}
};

///---------------------------------------------------------------------------------------

class Square : public BaseRectangle { //kwadrat

	friend std::ostream& operator<<(std::ostream&, const BaseRectangle&);

	virtual std::ostream& operator<<(std::ostream& os) const { //taka sama sytuacja
		os << "dimension = " << dimension << std::endl;
		os << "pos(x,y) = ( " << returnPos().x << ", " << returnPos().y << " )\n";
		return os;
	}

private:
	int dimension;
public:

	Square(int d=0, int x=0, int y=0) : BaseRectangle(x, y), dimension(d) {}

	virtual long area() {
		return dimension*dimension;
	}

};

///---------------------------------------------------------------------------------------

std::ostream& operator<<(std::ostream& os, const BaseRectangle& bs) {
	bs << os; //wywołanie prywatnej metody 
//operatora<< w zależności od podanego argumentu
	return os;
}

Błędy kompilacji jaki mam:

Jestem w temacie dziedziczenia jeszcze bardzo zielony, trochę tu nakombinowałem i musiałem coś zawalić, wiecie może co? Czy w ogóle dobrze myślałem/kombinowałem nad sposobem rozwiązania tego problemu?

Z góry bardzo wam dziękuje za pomoc ;)

komentarz zamknięcia: dostałem treściwą odpowiedź

1 odpowiedź

0 głosów
odpowiedź 3 czerwca 2018 przez monika90 Pasjonat (22,940 p.)
wybrane 3 czerwca 2018 przez Jakub 0
 
Najlepsza

Definicje funkcji w plikach nagłówkowych powinny mieć atrybut inline

Radziłabym nazwać funkcję wirtualną jakoś inaczej, bo teraz można się pogubić, np:

virtual void print(std::ostream&) const = 0;

oraz używać override.

Nie ma też potrzeby zaprzyjaźniania operatora << z każdą klasą pochodną.

komentarz 3 czerwca 2018 przez Jakub 0 Pasjonat (23,120 p.)
Dziękuje za pomoc, teraz to wszystko wygląda zgrabniej. Ale że tak się zapytam, bo nadal nie jestem pewny. Co było właściwie przyczyną wcześniejszego błędu kompilacji?
1
komentarz 3 czerwca 2018 przez monika90 Pasjonat (22,940 p.)
Pewnie inkludowałeś plik z definicją operatora << w dwóch plikach cpp, więc miałeś dwie definicje, a to jest niedopuszczalne dla funkcji (i zmiennych), no chyba że są inline, to wtedy można mieć wiele definicji te samej funkcji lub zmiennej, pod warunkiem, że te definicje są identyczne.

Powinieneś też coś zrobić z destruktorem w klasie bazowej, np. zdefiniować jej publiczny wirtualny destruktor.
komentarz 3 czerwca 2018 przez Jakub 0 Pasjonat (23,120 p.)
Faktycznie :/

Z tym destruktorem wirtualnym to wiem że jest ważny ale na śmierć go ciągle zapominam wstawić. Co do funkcji zaprzyjaźnionej niby też wiedziałem że powinna być w pliku .cpp albo być inline. Jednak o tym też zapomniałem ( i nie zauważyłem że dodaję ten plik nagłówkowy do innych plików programu ). A najgorsze jest to że sam na to nie wpadłem... ;(

Podobne pytania

0 głosów
2 odpowiedzi 348 wizyt
0 głosów
1 odpowiedź 1,157 wizyt
pytanie zadane 26 listopada 2016 w C i C++ przez sofnir Gaduła (4,690 p.)
0 głosów
1 odpowiedź 156 wizyt

92,454 zapytań

141,263 odpowiedzi

319,099 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...