wczytywanie do vectora

0

Witam, czy mógłby mi ktoś podpowiedzieć co mam zrobić aby mój kod był bardziej elegancki. Otóź, mam klase w której jest metoda wczytująca dane z pliku do jakiegoś vectora obiektów tej klasy. Tutaj pojawia się mój problem, bo później w programie muszę powołać do życia jeden obiekt tejże klasy i z niego wywołać metodę wczytującą dane. Wydaje mi się że to nie jest idealne rozwiązanie. Mógłby ktoś poradzić jak zrobić żeby wyglądało to lepiej?

 
class Linia
{
private:
    int typ;
    int numer;
    vector <int> trasa;
public:
    Linia(int t=0,int nr=0, vector <int> tra={})
    {
        typ=t;
        numer=nr;
        trasa=tra;

    }
 void wczytajLinie(vector <Linia> &l,string nazwa_pliku);

int main()
{
Linia k;
vector <Linia> linie;
k.wczytajLinie(linie,"linie.txt");
}
0

Po pierwsze po co definiujesz wyspecjalizowany konstruktor, którego w ogóle nie używasz?
Po drugie próbujesz przekazać wektor przez wartość. Jeżeli już to przekaż do wskaźnika wewnątrz klasy jego adres albo na żywca przepisz zawartość jednego do drugiego pętlą (gorsze rozwiązanie).
Po trzecie w C++ używaj listy inicjalizacyjnej do inicjalizowania w konstruktorze pól klasy.
Po czwarte zamiast przekazywać wektor intów zrób funkcję, która będzie dodawała wartości do wektora będącego polem klasy.

#include <iostream>
#include <vector>
using namespace std;

class Linia
{
	public:
		Linia() : typ(0), numer(0), trasa(nullptr){}
		Linia(vector<int> &tra, int t, int nr) : typ(t), numer(nr), trasa(&tra){}
		void wczytajLinie(string nazwa_pliku){
			//	Tutaj odczytaj plik i zapełnij pola składowe klasy.
		}

	private:
		int typ;
		int numer;
		vector <int> *trasa;
};
 
int main()
{
	vector<int> test;
	Linia nowa(test, 10, 10);
}
0

Konstruktora użyłem w funkcji wczytajLinie mniej więcej tak:

 
Linia nowa_linia(typ,numer,trasa_linii);
              l.push_back(nowa_linia);
1

Zasada jednej odpowiedzialności. Kod odpowiedzialny za wczytywanie danych powinien być wydzielony do osobnej klasy.

0

To tak nie powinno być. Nie rób takich łańcuszków, bo później nie połapiesz się co gdzie się wykonuje. Posłuchaj rady Patryka i zrób sobie np klasę (statyczną najlepiej), która będzie odczytywała dane z pliku.

0

Jak taka klasa miałaby wyglądać? Mam dwie klasy Linia i Przystanek do których wczytuje z pliku.

0

Tak np:

class Plik{
	public:
		static void odczytaj(Linia &obj, string nazwa_pliku){

		}
};
 
int main()
{
	Linia nowa;
	Plik::odczytaj(nowa, "plik.txt");
}
0

a jak tą klasę Plik połączyć jakoś w spójną całość na diagramie klas?

0

Dobra załóżmy, nie chcę robić oddzielnej klasy do wczytywania z pliku. Czy możecie mi coś innego doradzić?

0

To po prostu wczytuj dane za pomocą funkcji wewnątrz klas Linia etc... jak zresztą zamierzałeś zrobić.

0

Dobra jednak oddzielną klasę plik, hehe. Czyli takie rozwiązanie przeszłoby w tłumie?

 
Linia k;
vector <Linia> linie;
k.wczytajLinie(linie,"linie.txt")

No i jeszcze jedno pytanie ta nowo stworzona przeze mnie klasa Plik, w której wczytuje sobie dane jak łączy się z klasą Linia (kompozycja?, agregacja?). Nie wiem jak to na diagramie klas oznaczyć.

0

Bez sensu to robisz. Po co tworzysz obiekt klasy do obsługi plików. Zrób po prostu klasę statyczną do obsługi plików. Wtedy nie będziesz musiał tworzyć jej obiektu, a tym samym nie będziesz się zastanawiał nad tym gdzie ją "wkomponować".

EDIT: poza tym zauważyłem, że to nie jest osobna klasa do odczytu pliku tylko dalej korzystasz z funkcji klasy Linia więc koło się zamyka. (mowa o kodzie, który dałeś post wyżej)

0

Napisałem przecież, że skorzystam z klasy Plik, gdzie będę miał metodę statyczną, tak jak mi zaproponowałeś, przecież. Ostatni post odnosił się do mojego pierwszego postu....

0
class Plik
{
public:
   static void wczytajPrzystanki(string nazwa_pliku, vector <Przystanek> &p);
   static void wczytajLinie(string nazwa_pliku, vector <Przystanek> &p);
};

......

Plik p;
vector <Przystanek> przystanki;
p.wczytajPrzystanki("mapa_przystankow.txt",przystanki);
 

Czy tak będzie ok?

0

Po co tworzysz obiekt skoro klasa ma być statyczna?

Plik::wczytajPrzystanki("mapa_przystankow.txt",przystanki);
0

Dobra rzeczywiście pomyliłem się z tym. Dziękuję bardzo za pomoc.

0

Uroki C++. Że też nie mogę sobie static przed klasą napisać i wszystko byłoby jasne przy próbie utworzenia obiektu ale nieeee... Kompilator sobie to zignoruje ładnie i ma w nosie :)

0

Czy do wczytania rozkładu jazdy z pliku w takiej postaci:
numer_linii
7:30 9:40 11:28
7:34 9:44 11:32
7:39 9:49 11:37
7:42 9:52 11:40
7:46 9:56 11:44
7:50 10:00 11:48
, gdzie wiersze odpowiadają kolejnym przystankom, a kolumny kolejnym odjazdom, dobrym pomysłem byłby zastosowanie vectora vectorów typu string?

1

Wektor krotek będzie dobry, (jeżeli reprezentacja wiersza składa się tak jak u Ciebie z trzech kolumn), ewentualnie wektor obiektów własnej klasy:

vector<tuple<string,string,string>> rozklad;

albo:

class Rekord{

// Oczywiście dostęp publiczny tylko dla potrzeb przykładu.
public:
	list<string> godziny;
};
 
int main()
{
	vector<Rekord*> rozklad;
}

albo w ogóle skorzystać jeszcze bardziej z kompozycji i zrobić taki wrapper:

class Rekord{
public:
	list<string> godziny;
};

class Rozklad{
public:
	vector<Rekord*> wiersz;
};
 
int main()
{
	Rozklad rz;
}
0

Hmm... nie bardzo widzę jakby miało to działać (ostatni sposób). Mając obiekt klasy Rekord zczytuje sobie pierwszy wiersz z pliku do vectora stringów. Następnie tworze obiekt klasy Rozklad i do niego powinienem wczytywać kolejne rekordy, tylko w jaki sposób? Do pliku wprowadziłem sobie jakiś znak który sugeruje koniec linii. Działa to tak że wczytuje pierwszą linię do tej tablicy stringów i nie wiem jak mam przejść do następnej. Jakieś porady? Nie mogę przecież tutaj skorzystać z funkcji getline .

0

Czy taka implementacja będzie w porządku grzesiek51114? Możesz ocenić czy to ma sens co napisałem?

 
class Rekord
{
 vector <string> odjazdy;
public:
   void wczytajRekord(ifstream &plik, vector <string> odj)
    {
            string odjazd;
            plik>>odjazd;
           while(odjazd!=":"&&odjazd!="") // : -> ten znak mam na końcu każdej linii w pliku oraz "" -> zeby petla sie skonczyla
          {
              odj.push_back(odjazd);
              plik>>odjazd;
        }
    }
};

class Rozklad
{
    vector <Rekord> odjazdy;
public:
    void wczytajRozklad(string nazwa_pliku,vector <Rekord> roz)
    {
        Rekord rek;
        ifstream plik;
        vector <string> odj;
          ..... // otwieranie pliku itd.
       
               while(!plik.eof())
           {
               rek.wczytajRekord(plik,odj);
               roz.push_back(rek);
           }

        }


    }

};

//main.cpp
vector <Rekord> rozklad;
Rozklad roz;
roz.wczytajRozklad("57.txt",rozklad);
0

W powyższym poście były błędy, bo nie korzystałem z atrybutu klasy a dodawałem do vectora będącego parametrem funkcji.
Czy ten kod będzie ok?

 
class Rekord
{
 vector <string> odjazdy;
public:
   void wczytajRekord(ifstream &plik)
    {
        Rekord rek;
        string odjazd;
            plik>>odjazd;
          while(odjazd!=":"&&odjazd!="")
          {
              rek.odjazdy.push_back(odjazd);
              cout<<odjazd<<" ";
              plik>>odjazd;
        }
        cout<<endl;
    }
};

class Rozklad
{
    vector <Rekord> odjazdy;
public:
    void wczytajRozklad(string nazwa_pliku)
    {
        Rozklad rozkl;
        Rekord rek;
        ifstream plik;
        vector <string> odj;
      
               while(!plik.eof())
           {
               rek.wczytajRekord(plik);
               rozkl.odjazdy.push_back(rek);
           }

        }
};

main.cpp

Rozklad roz;
roz.wczytajRozklad("57.txt");

0

Ja bym to np. zrobił w ten sposób:

#include <iostream>
#include <vector>
#include <fstream>
#include <string>
using namespace std;

class Wiersz{
	public:
		void dodajCzas(string czas){
			this->godziny.push_back(czas);
		}

		vector<string> &zwrocGodziny(){
			return this->godziny;
		}

	private:
		vector<string> godziny;
};

class Rozklad{
	public:
		void dodajWiersz(const Wiersz &wiersz){
			this->wiersze.push_back(wiersz);
		}

		vector<Wiersz> &zwrocWiersz(){
			return this->wiersze;
		}

		void wypiszRozklad(){
			for (unsigned i = 0; i < wiersze.size(); i++){
				cout << i + 1 << ". ";
				for (unsigned j = 0; j < wiersze.at(i).zwrocGodziny().size(); j++)
					cout << wiersze.at(i).zwrocGodziny().at(j) << " ";
				cout << endl;
			} 
		}

	private:
		vector<Wiersz> wiersze;
};

class Plik{
	public:
		static void odczytaj(Rozklad &roz, string nazwaPliku){
			fstream plik(nazwaPliku, ios::in);
			if (plik.is_open()){
				string dane = "";
				size_t poz = 0;
				int i = 0;

				while (getline(plik, dane)){
					roz.dodajWiersz(Wiersz());
					while ((poz = dane.find(" ")) != string::npos){
						roz.zwrocWiersz().at(i).dodajCzas(dane.substr(0, poz));
						dane.erase(0, poz + 1);
					}
					i++;
				}
				plik.close();
			}
			else cout << "Blad odczytu\n";
		}
};

int main()
{
	Rozklad rozklad;
	Plik::odczytaj(rozklad, "lista.txt");
	rozklad.wypiszRozklad();
	system("pause");
	return 0;
}

PS: ech... rozleniwiłem się przy C#. Człowiek nie musi wiecznie szukać potrzebnych funkcji takich jak np. string split, albo martwić się tym czy przesyła obiekt przez wskaźnik czy przez wartość...:)

0

Jaki jest sens tworzenia klasy, która ma tylko jedną metodę i to w dodatku statyczną?
Jaki jest sens tworzenia klas, które są jota w jotę zwykłym wektorem?

Chyba rzeczywiście C# namieszał Ci za bardzo w głowie.

0

Dobra a teraz mam kolejny problem. Mam wczytane obiekty klasy Linia do wektora. Do klasy linia dodałem sobie atrybut typu Rozklad. Jak mam wczytywać ( a raczej przepisać dane z obiektu do którego już je wczytałem) i zapisywać a atrybucie typu Rozklad? Wygląda to mniej więcej tak:


class Linia
{
private:
    int typ;
    int numer;
    vector <int> trasa;
    Rozklad rozklad_jazdy_Linii;
public:
    Linia(int t=0,int nr=0, vector <int> tra={},Rozklad rjl={})
    {
        typ=t;
        numer=nr;
        trasa=tra;
        rozklad_jazdy_Linii=rjl;

    }
....
};
class Rozklad
{
    vector <Rekord> rozklad_jazdy;
public:
    void wczytajRozklad(string nazwa_pliku);
};
class Rekord
{
 vector <string> odjazdy;
public:
   void wczytajRekord(ifstream &plik);
};
 
0

dobra to powyżej nieważne, już sobie poradziłem z tym problemem. Mam takie pytanie: czy utworzenie wektora stringów nazw plików z których wczytywany miałby być rozkład jest dobrym pomysłem?

0

Dzięki za szybką opowiedź, po prostu jestem początkujący i mam mało czasu i nie chce tracić go na nietrafne pomysły.

0

Ok teraz potrzebuje konkretnej porady, ponieważ stanąłem w martwym punkcie. Mam wczytane dane z plików do vectorów (przystanki i linie), na podstawie tych danych tworze sobie vector vectorów typu int który stanowi macierz sąsiedztwa (mam zatem graf otrzymany z wczytanych linii, vector vectorów jest typu int ponieważ przystanki są numerowane). Z macierzy sąsiedztwa wyszukuję sobie połączenie z punktu a do b na podstawie algorytmu dijkstry.
I pytanie: Jak zrobić aby algorytm djikstry "zwracał też uwagę" na trasy danych linii, ponieważ obecnie wyszukując trasę z punktu a do b wyznacza mi tę odległość w taki sposób jakby graf był tworzony przez jedną linię ( a chciałbym zrobić tak aby algorytm sugerował przesiadki itp.)
II pytanie: jak mam zmodyfikować implementację algorytmu dijkstry aby szukał zarówno z punktu a do b oraz z b do a?

#define ilosc_wierzcholkow 10 

static void wyszukajLinie(vector <vector <int> > &macierz_sasiedztwa, int skad, int dokad)
    {
        int odleglosci[ilosc_wierzcholkow];  

        bool QS[ilosc_wierzcholkow];
                                       
     for (int i = 0; i < ilosc_wierzcholkow; i++)
    {
        odleglosci[i] = INT_MAX,
        QS[i] = false;
    }

     odleglosci[skad] = 0; // odleglosc od zrodla do zrodla =0

     for (int i= 0; i <ilosc_wierzcholkow; i++) 
     {
       int u = minOdleglosc(odleglosci,QS); 
                                            

       QS[u] = true;  
       for (int j=0;j<ilosc_wierzcholkow;j++) 
        {

         if (!QS[j] && macierz_sasiedztwa[u][j] && odleglosci[u]!= INT_MAX&& odleglosci[u]+macierz_sasiedztwa[u][j] < odleglosci[j])
            {
                odleglosci[j] = odleglosci[u] + macierz_sasiedztwa[u][j];

            }
        }
     }
drukujWyszukanePolaczenie(odleglosci,skad,dokad);
    }

};



 
main.cpp

vector <Przystanek> przystanki;
vector <Linia> linie;
Plik::wczytajPrzystanki("mapa.txt",przystanki);
Plik::wczytajLinie("l.txt",linie,nazwy_plikow);
Linia::tworzMacierzSasiedztwa(linie,macierz_sasiedztwa,przystanki);
Linia::wyszukajLinie(macierz_sasiedztwa,4,0);

0

Poradzi ktoś coś do mojego powyższego postu?

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