Konstruktor klasy wywołujący metodę ustawiającą wartości składników klasy

0

Cześć, piszę program, który ma za zadanie analizować podstawowe dane plików .gpx (w plikach .gpx zapisane są np treningi rowerowe itp). Skorzystałem z parsera xml (tinyxml2). Mam jednak problem. Stworzyłem klasę GPXData. Zawiera ona nazwę analizowanego pliku, strukturę z parametrami pliku (struktura przechowuję vectory z położeniem, czasem i wysokością), oraz metodę readData która zawiera całe instrukcję do parsera i aktualizuję parametry danego obiektu klasy GPXData. Chciałem zrobić coś takiego, że w main tworząc obiekt podajemy nazwę interesującego nas pliku gpx, którego konstruktor automatycznie wywoła metodę readData, a ona uzupełni pozostałe parametry obiektu. Jednak nie działa to po mojej myśli. Po głębszym zastanowieniu, nie dziwię się bardzo, że coś tu nie działa, ale nie mam pomysłu jak zrobić to tak, aby wszystko miało sens. Poniżej mój kod:

#ifndef GPXSTATS_GPXDATA_H
#define GPXSTATS_GPXDATA_H

#include <iostream>
#include <vector>

struct GPXParameter
{
    std::vector<double> lats;
    std::vector<double> lons;
    std::vector<double> eles;
    std::vector<const char*> times;
};

class GPXData
{
public:
    GPXData(char*);

private:
    char* nameFile;
    GPXParameter parm;
    void readData(char* titleGPX);

};


#endif //GPXSTATS_GPXDATA_H

#include <iostream>
#include <cassert>
#include <tinyxml2.h>

#include "GPXData.h"

GPXData::GPXData(char* nameFile) : nameFile(nameFile)
{
    this->readData(nameFile);
}

void GPXData::readData(char* titleGPX)
{
    tinyxml2::XMLNode *gpx = nullptr;
    tinyxml2::XMLNode *trk = nullptr;
    tinyxml2::XMLNode *trkseg = nullptr;
    tinyxml2::XMLError result;

    tinyxml2::XMLDocument docGPX;
    docGPX.LoadFile(titleGPX);
    tinyxml2::XMLNode* root = docGPX.FirstChild();
    if(root == nullptr)
        std::cout << "Cannot open file" << std::endl;

    docGPX.Print(); // TESTOWE

    gpx = docGPX.FirstChildElement("gpx");
    assert(gpx);
    trk = gpx->FirstChildElement("trk");
    assert(trk);
    trkseg = trk->FirstChildElement("trkseg");
    assert(trkseg);

    for (tinyxml2::XMLElement *trkpt = trkseg->FirstChildElement("trkpt"); trkpt; trkpt = trkpt->NextSiblingElement("trkpt"))
    {
        double lat, lon, el;
        result = trkpt->QueryDoubleAttribute("lat", &lat);
        assert(result == tinyxml2::XML_SUCCESS);
        result = trkpt->QueryDoubleAttribute("lon", &lon);
        assert(result == tinyxml2::XML_SUCCESS);

        parm.lats.push_back(lat);
        parm.lons.push_back(lon);

        tinyxml2::XMLElement *ele = trkpt->FirstChildElement("ele");
        assert(ele);

        result = ele->QueryDoubleText(&el);
        assert(result == tinyxml2::XML_SUCCESS);

        parm.eles.push_back(el);

        tinyxml2::XMLElement *TimeDate = trkpt->FirstChildElement("time");
        assert(TimeDate);

        const char* time = TimeDate->GetText();

        parm.times.push_back(time);

    }

}

#include <iostream>
#include <vector>
#include <cassert>
#include <ctime>
#include <time.h>
#include <tinyxml2.h>

#include "GPXData.h"

using namespace tinyxml2;
using namespace std;

void readData(const char* titleGPX);

int main()
{
    char* nameOfFirstFile = "Lunch_Ride.gpx";
    std::string test2= "Lunch_Ride.gpx";

    GPXData file1(nameOfFirstFile);

    return 0;
}

Błąd

====================[ Build | GPXStats | Debug ]================================
"C:\Program Files\JetBrains\CLion 2021.2.3\bin\cmake\win\bin\cmake.exe" --build "C:\Users\Dell\Documents\Studia\Projekty C++\GPXStats\cmake-build-debug" --target GPXStats
[1/1] Linking CXX executable GPXStats.exe
FAILED: GPXStats.exe 
cmd.exe /C "cd . && C:\PROGRA~1\MINGW-~1\X86_64~1.0-P\mingw64\bin\C__~1.EXE -g  CMakeFiles/GPXStats.dir/main.cpp.obj -o GPXStats.exe -Wl,--out-implib,libGPXStats.dll.a -Wl,--major-image-version,0,--minor-image-version,0  C:/tinyxml2/lib/libtinyxml2.a  -lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 && cd ."
CMakeFiles/GPXStats.dir/main.cpp.obj: In function `main':
C:/Users/Dell/Documents/Studia/Projekty C++/GPXStats/main.cpp:20: undefined reference to `GPXData::GPXData(char*)'
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
2

W jakiej to masz platformie?

Wygląda, jakbyś nie miał modułu źródłowego CPP w projekcie .

0
ZrobieDobrze napisał(a):

W jakiej to masz platformie?

Wygląda, jakbyś nie miał modułu źródłowego CPP w projekcie .

Ale zagmatwałem. Masz rację, nie dopisałem pliku cpp w cmake. Miałem długą przerwę w nauce cpp, więc wyleciało mi to z głowy. Teraz wszystko chyba działa. Pozostaje mi zadać pytanie czy to co zrobiłem to dobra praktyka, czy raczej unika się takich rozwiązań.

1

Obstawiam że w std::vector<const char*> times; masz albo śmiecie albo ostatnią wczytaną wartość, w zależności od konstrukcji: TimeDate->GetText();

0
_13th_Dragon napisał(a):

Obstawiam że w std::vector<const char*> times; masz albo śmiecie albo ostatnią wczytaną wartość, w zależności od konstrukcji: TimeDate->GetText();

Faktycznie masz rację. Udało mi się dojść chyba do przyczyny. Nie można używać push_back z wskaźnikami tak? W takim razie jakie jest najlepsze rozwiązanie? Póki co rzutuje to do stringa (w strukturze też zmieniłem typ pola) i działa, ale nie wiem czy tak powinno się rozwiązywać tego typu problemy.

0

Wg mnie powinno być:

struct GPXParameterItem
{
    double lat,lon,ele;
    TimeDate time;
};
typedef vector<GPXParameterItem> GPXParameter;

To: GPXData::GPXData(char* nameFile) : nameFile(nameFile) nie zadziała jeżeli nameFile zostanie wczytany dynamicznie.
Tak a propos po kiego coś zapisujesz do zmiennej składowej skoro i tak wywołujesz: this->readData(nameFile); tak a propos ten this-> też nie jest potrzebny.

void readData(const char* titleGPX); co to niby ma być i po kiego?

Sugerowałbym jakiś współczesny kurs C++ od podstaw.

0
janullo789 napisał(a):

Faktycznie masz rację. Udało mi się dojść chyba do przyczyny. Nie można używać push_back z wskaźnikami tak?

Można, ale trzeba wiedzieć co to znaczy: kolekcja gołych wskaźników i nic więcej. Które to gołe wskaźniki w międzyczasie mogą utracić swoją ważność - więc to chyba nie jest dobry pomysł do przechowywania stringów.

W takim razie jakie jest najlepsze rozwiązanie?

std::vector<std::string> times;

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