Opracuj tablicę klasy - program do sprawdzenia

0

Witam serdecznie,
muszę napisać program wypełniający założenia zadania o następującej treści :

Opracuj klasę TablicaPlyt, która pozwala administrować zbiorem obiektów klasy TPlyta. W klasie TPlyta przechowywana jest informacja o płycie w postaci: wykonawca, tytuł płyty i cena. W klasie TablicaPlyt przechowywane są obiekty typu TPlyta. Klasy mają umożliwiać w szczególności :

  1. dodanie płyt za pomocą konstruktora
  2. dodawanie płyty do tablicy płyt za pomocą przeciążonego operatora <<
  3. wyświetlanie zawartości obiektu wskazanego za pomocą indeksu w tablicy za pomocą przeciążonego operatora <<
  4. usuwanie z tablicy płyty o wskazanym indeksie
  5. zapisać tablicę płyt do pliku
  6. wczytać opisy płyt z pliku do tablicy
  7. wyświetlić tytuł płyty o najmniejszej cenie
  8. wyświetlić wykaz wszystkich płyt

ZWRACAM się z uprzejmą prośbą o sprawdzenie programu. Wszelkie uwagi są bardzo mile widziane :)
Pozdrawiam serdecznie
student_RRK

 
```// ConsoleApplication1.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <iostream>
#include <algorithm>


using namespace std;
class Plyta
{
private:
	string wykonawca;
	string tytul;
	double cena;
public:
	Plyta() {};
	Plyta(string wykonawca, string tytul, double cena)
	{
		this->wykonawca = wykonawca;
		this->tytul = tytul;
		this->cena = cena;
	}
	double get_cena() const
	{
		return cena;
	}

	string toString()
	{
		return (wykonawca + " " + tytul + " " + to_string(cena) + "\n");
	}
	friend ostream & operator<<(ostream & wy, Plyta & plyt) {
		return wy << "Wykonawca:  " << plyt.wykonawca << ",  tytul:  " << plyt.tytul << ", cena: " << plyt.cena << endl;
	}
};
class TablicaPlyt
{
private:
	
	vector<Plyta> Plyty;
	
public:
	TablicaPlyt(int rozmiar)
	{
		Plyty.reserve(rozmiar);
	}
	void operator+(Plyta& p)
	{
		Plyty.push_back(p);
	}

	
	void save()
	{

		ofstream plik("D:/plik.txt");
		for (vector<Plyta>::iterator i = Plyty.begin(); i<Plyty.end(); i++)
			plik << i->toString();
		plik.close();
		
	}

	void load()
	{
		ifstream plik("D:/plik.txt");

		while (plik)
		{

			string wykonawca, tytul, cena;
			plik >> wykonawca >> tytul >> cena;

			if(!plik.eof()){
				Plyta tmp(wykonawca, tytul, atof(cena.c_str()));
				Plyty.push_back(tmp);
			}
				

			
			
		}
	}
	Plyta& operator[](int element)
	{
		return Plyty[element];
	}
	void usun(int element) {
		Plyty.erase(Plyty.begin() +element);
	}
	~TablicaPlyt() {
		Plyty.clear();
	}

	void drukujTest()
	{
		cout << "\n\nAktualny rozmiar: " << Plyty.size() << endl << endl;
		cout << "Aktualne elementy " << endl;

		for (vector<Plyta>::iterator i = Plyty.begin(); i<Plyty.end(); i++)
			cout << i->toString();
		cout << "-*-*-*-*-*-*-*-*-*-" << endl;
	}

	void drukujNajtansze()
	{
		
		cout << "\n\nNajtansza plyta to : \n\n";
		int min = Plyty[0].get_cena();
		int indeks_min = 0;
		for (unsigned i = 1; i < Plyty.size(); i++)
		{
			
			if (Plyty[i].get_cena() < min) 
			{
				min = Plyty[i].get_cena();
				indeks_min = i;
			}
			
				
		}

		cout << Plyty[indeks_min].toString();
	
	}
};
int main() {
	Plyta p1("Bach", "Fuga", 22.50);
	Plyta p2("Rolling", "Stone", 49.99);
	Plyta p3("Celin", "Show", 100.20);
	Plyta p4("Freddy", "Hot", 115.40);
	Plyta p5("Metalica", "Dark", 19.99);
	Plyta p6("Nirvana", "Luna", 50.90);
	Plyta p7("Rihana", "Love", 90.20);
	Plyta p8("The", "Winter", 115.40);
	Plyta p9("Red", "Onion", 10.99);
	Plyta p10("Brain", "Feel", 30.90);


	TablicaPlyt tabP(10);
	tabP + p1;
	tabP + p2;
	tabP + p3;
	tabP + p4;
	tabP + p5;
	tabP + p6;
	tabP.drukujTest();
	tabP.usun(1);
	cout << "Tablica plyt po usunieciu jednej pozycji: " << endl << endl;
	tabP.drukujTest();
	tabP.save();




	


	cout << "\n\n\n\nNOWA TABLICA WCZYTANA Z PLIKU";
	TablicaPlyt nowatab(10);
	nowatab.load();
	nowatab.drukujTest();

	nowatab.drukujNajtansze();

	system("pause");
	return 0;
}



0

Rzucił mi się w oczy operator+. Normalnie + dodaje dwa operandy i zwraca wynik lub jest operatorem "nie"zmiany znaku. To powinna być zwykła metoda typu void dodaj(const Plyta& p);. Wtedy nie będzie potrzeby tworzenia dziesięciu obiektów tylko wystarczy

tabP.dodaj(Plyta{"Bach", "Fuga", 22.50});

W kostruktorze skorzystaj z listy inicjalizacyjnej.

0

Dziękuję serdecznie za odpowiedź :)

1

Prosiłeś o sprawdzenie. Sam prosiłeś :-)

// ConsoleApplication1.cpp : Defines the entry point for the console application.
//
// XXX: Kopilować zgodnie ze standardem C++11
#include "stdafx.h"
#include <fstream>
#include <string>
#include <vector>
#include <cstdlib>
#include <iostream>
#include <algorithm>

using namespace std;

class Plyta {
private:
    string wykonawca;
    string tytul;
    double cena;
public:
    // XXX: Lepiej wyrazić jasno że chodzi o konstruktor domyślny
    //Plyta() {};
    Plyta() = default;
    // Plyta(string wykonawca, string tytul, double cena) {
    // XXX: To co wyżej będzie "ciężkie". Tu w trakcie wywołania będą wykonane kopie string'ów.
    // XXX: Warto użyć list inicjalizacyjnych.
    Plyta(const string& wykonawca, const string& tytul, double cena)
        : wykonawca{wykonawca}, tytul{tytul}, cena{cena} {
    }
    double get_cena() const {
        return cena;
    }
    // XXX: Tu nie dochodzi do zmiany atrybutów klasy więc..
    //string toString() {
    string toString() const {
        return (wykonawca + " " + tytul + " " + to_string(cena) + "\n");
    }
    friend ostream& operator<<(ostream& wy, Plyta& plyt) {
        return wy << "Wykonawca:  " << plyt.wykonawca << ",  tytul:  " <<
               plyt.tytul << ", cena: " << plyt.cena << endl;
    }
};

class TablicaPlyt {
private:
    vector<Plyta> Plyty;
public:
    // XXX: size_t zamiast int. Rozmiary kontenerów są w typie size_t a nie int.
    // Pomyśl. Kontener może mieć ujemny rozmiar? :-)
    //TablicaPlyt(int rozmiar) {
    TablicaPlyt(size_t rozmiar) {
        Plyty.reserve(rozmiar);
    }
    // XXX: Lepiej zrobić dodaj() i zwrócić "siebie". Wtedy będziesz mógł robić taki 
    // "pociąg": tablicaPlyt.dodaj(plyta1).dodaj(plyta2).dodaj(plyta3);
    //void operator+(Plyta& p) {
    TablicaPlyt& dodaj(Plyta& p) {
        Plyty.push_back(p);
        return *this;
    }
    // XXX: Dodaj const. save() nie zmienia atrybutów
    //void save() {
    void save() const {
        ofstream plik("D:/plik.txt");
        // XXX: Brakuje sprawdzenia czy plik udało się otworzyć poprawnie.

        // XXX: Wygodniejszą pętlą będzie for zakresu
        //for(vector<Plyta>::iterator i = Plyty.begin(); i < Plyty.end(); i++)
        //{ plik << i->toString(); }
        for(const auto& plyta: Plyty) {
            plik << plyta.toString();
        }

        // XXX: Nie trzeba zamykać pliku otwartego w bloku kodu. Plik zostanie
        // automatycznie zamknięty przez destruktor.
        //plik.close();
    }

    void load() {
        ifstream plik("D:/plik.txt");
        // XXX: Znów brakuje testu czy plik poprawnie otworzony.

        while(plik) {
            // XXX: Puryści pewnie by się czepiali że warto definiować w 1 linii 1 zmienna.
            // To trochę "upierdliwość" ale powinieneś wiedzieć :-)
            //string wykonawca, tytul, cena;
            string wykonawca;
            string tytul;
            // XXX: Nie widzę formatu danych. Może zawiera jakieś śmieci przy cenie
            // i masz powód by traktować ją jako sting, ale jeśli nie to lepiej 
            // zmienić ją na double.
            //string cena;
            double cena;
            plik >> wykonawca >> tytul >> cena;

            if(!plik.eof()) {
                // XXX: Wynika ze zmiany ceny na double
                //Plyta tmp(wykonawca, tytul, atof(cena.c_str()));
                Plyta tmp(wykonawca, tytul, cena);
                Plyty.push_back(tmp);
            }
        }
    }
    // XXX: indeksy są w typie size_t
    //Plyta& operator[](int element) {
    Plyta& operator[](size_t element) {
        return Plyty[element];
    }
    // XXX: To samo. size_t
    //void usun(int element) {
    void usun(size_t element) {
        Plyty.erase(Plyty.begin() + element);
    }
    // XXX: TU destruktora nie potrzeba bo w atrybutach masz kontener
    // tworzony na stosie i trzyma on kopie. Jak byś trzymał jekieś wskaźniki,
    // to trzeba by było "ładnie" usunąć. Tu nie.. 
    //~TablicaPlyt() {
    //    Plyty.clear();
    //}

    // XXX: Brakuje const. Metoda nie zmienia atrybutów.
    void drukujTest() const {
        // XXX: Trochę nadmiarowe czyszczenie bufora. endl wyprowadza \n 
        // i robi flush. W zasadzie wystarczy to robić 1 raz.
        //cout << "\n\nAktualny rozmiar: " << Plyty.size() << endl << endl;
        //cout << "Aktualne elementy " << endl;
        cout << "\n\nAktualny rozmiar: " << Plyty.size() << "\n\n"
            << "Aktyalne elementy " << endl; // XXX: Albo i nawet na końcu metody.. 

        // XXX: Znów, lepiej for zakresowym.
        //for(vector<Plyta>::iterator i = Plyty.begin(); i < Plyty.end(); i++)
        //{ cout << i->toString(); }
        for(const auto& plyta: Plyty) {
            cout << plyta.toString();
        }

        cout << "-*-*-*-*-*-*-*-*-*-" << endl;
    }

    // XXX: Brakuje const
    //void drukujNajtansze() {
    void drukujNajtansze() const {
        // XXX: Uwaga ogólna. Tu możesz użyć algorytmu min_element()
        // Tu nie będę poprawiał kodu tylko umieszczę poniżej rozwiązanie z min_element
        // Dodasz nagłówek <algorithm> i sprawdzisz :-)
        cout << "\n\nNajtansza plyta to : \n\n";
        // XXX: get_cena() zwraca double
        //int min = Plyty[0].get_cena();
        double min = Plyty[0].get_cena();
        // XXX: Indeks jest size_t
        //int indeks_min = 0;
        size_t indeks_min = 0;
        
        for(unsigned i = 1; i < Plyty.size(); i++) {
            if(Plyty[i].get_cena() < min) {
                min = Plyty[i].get_cena();
                indeks_min = i;
            }
        }
        cout << Plyty[indeks_min].toString();

        /* XXX: Propozycja z min_element().... 
         * Od razu return.. 
        return (*min_element(Plyty.cbegin(), Plyty.cend(),
                [](const Plyta& plyta1, const Plyta& plyta2) {
                    return plyta1.get_cena() < plyta2.get_cena();
         })).toString();
        */
    }
};

int main() {
    // XXX: Tu nie mam uwag bo testy często pisze się "makaronem" :-)
    Plyta p1("Bach", "Fuga", 22.50);
    Plyta p2("Rolling", "Stone", 49.99);
    Plyta p3("Celin", "Show", 100.20);
    Plyta p4("Freddy", "Hot", 115.40);
    Plyta p5("Metalica", "Dark", 19.99);
    Plyta p6("Nirvana", "Luna", 50.90);
    Plyta p7("Rihana", "Love", 90.20);
    Plyta p8("The", "Winter", 115.40);
    Plyta p9("Red", "Onion", 10.99);
    Plyta p10("Brain", "Feel", 30.90);
    TablicaPlyt tabP(10);
    // XXX: Poprawione na dodaj() .. no to "pociąg" :-)
    //tabP + p1;
    //tabP + p2;
    //tabP + p3;
    //tabP + p4;
    //tabP + p5;
    //tabP + p6;
    tabP.dodaj(p1).dodaj(p2).dodaj(p3).dodaj(p4).dodaj(p5).dodaj(p6);
    tabP.drukujTest();
    tabP.usun(1);
    cout << "Tablica plyt po usunieciu jednej pozycji: " << endl << endl;
    tabP.drukujTest();
    tabP.save();
    cout << "\n\n\n\nNOWA TABLICA WCZYTANA Z PLIKU";
    TablicaPlyt nowatab(10);
    nowatab.load();
    nowatab.drukujTest();
    nowatab.drukujNajtansze();
    system("pause");
    // XXX: Lepiej zwracaj EXIT_SUCCESS z <cstdlib> lub nie zwracaj nic.
    // W c++ kompilator sam dopisuje return 0 w main() jeśli go nie ma.
    //return 0;
} 
0
Mokrowski napisał(a):

Prosiłeś o sprawdzenie. Sam prosiłeś :-)

Pewnie, że tak :) Twoja wypowiedź jest dla mnie niezwykle cenna, super jest zobaczyć tak rzeczową analizę kodu.

Pozdrawiam!

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