Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++] Dostęp do prywatnego wektora z innej klasy - program bazujący na UML

Ostatnio zmodyfikowano 2017-11-01 00:05
Autor Wiadomość
selveee
Temat założony przez niniejszego użytkownika
[C++] Dostęp do prywatnego wektora z innej klasy - program bazujący na UML
» 2017-10-31 20:59:11
Witam złote rączki, piszę z męczącym mnie od kilku dni problemem, który już prawie porzuciłem ( a muszę go rozwiązać i ukończyć cały projekt do niedzieli włącznie ): otrzymałem od prowadzącego wytyczne na temat kolejnego z projektów, wytyczne to schemat UML programu:


Link do zdjęcia UML


Link do skanu powyższego


Wszystko pięknie ładnie, napisałem program, podzieliłem go wstępnie na oddzielne pliki .h (dalszy wywód pod zawartością ostatniego pliku):



Plik z klasą Sygnal:
C/C++
#ifndef _Sygnal_h_
#define _Sygnal_h_
#include <iostream>
#include <vector>
#include "Probka.h"
using namespace std;
class Sygnal
{
private:
    vector < Probka > probki;
public:
    Sygnal() { }
    void dodajProbke( const Probka & _p )
    {
        probki.push_back( _p );
    }
    int iloscProbek()
    {
        return probki.size();
    }
    Probka & operator []( int i );
    friend ostream & operator <<( std::ostream & aStream, const Sygnal & aSygnal );
};
#endif

Plik z klasą Probka:
C/C++
#ifndef _Probka_h_
#define _Probka_h_
using namespace std;
class Probka
{
public:
    double t;
    double x;
    Probka();
    Probka( double _t, double _x )
    {
        t = _t;
        x = _x;
    }
    friend ostream & operator <<( ostream & aStream, const Probka & aProbka );
};
#endif

Plik z klasą AnalizatorSygnalu:
C/C++
#ifndef _AnalizatorSygnalu_h_
#define _AnalizatorSygnalu_h_
#include "Sygnal.h"
using namespace std;

class AnalizatorSygnalu
{
public:
    AnalizatorSygnalu() { }
    double dlugosc( const Sygnal & _sygnal )
    {
        double _min = _sygnal.probki[ 0 ].x;
        double _max = _sygnal.probki[ 0 ].x;
        for( int i = 0; i < _sygnal.probki.size(); i++ ) {
            if( _sygnal.probki[ i ].x < _min )
                 _min = _sygnal.probki[ i ].x;
           
            if( _sygnal.probki[ i ].x > _max )
                 _max = _sygnal.probki[ i ].x;
           
        }
        return _max - _min;
    }
   
    double minimum( const Sygnal & _sygnal )
    {
        double _min = _sygnal.probki[ 0 ].x;
        for( int i = 0; i < _sygnal.probki.size(); i++ ) {
            if( _sygnal.probki[ i ].x < _min )
                 _min = _sygnal.probki[ i ].x;
           
        }
        return _min;
    }
   
    double maksimum( const Sygnal & _sygnal )
    {
        double _max = _sygnal.probki[ 0 ].x;
        for( int i = 0; i < _sygnal.probki.size(); i++ ) {
            if( _sygnal.probki[ i ].x > _max )
                 _max = _sygnal.probki[ i ].x;
           
        }
        return _max;
    }
    double srednia( const Sygnal & _sygnal )
    {
        double m = 0.0;
        for( int i = 0; i < _sygnal.probki.size(); ++i ) {
            m += _sygnal.probki[ i ].x;
        }
        if( _sygnal.probki.size() > 0 ) {
            m /= _sygnal.probki.size();
        }
        return m;
    }
   
    double calka( const Sygnal & _sygnal )
    {
        double calka = 0, dt = 0, dpole = 0;
        for( int i = 0; i < _sygnal.probki.size(); i++ )
        {
            dt = _sygnal.probki[ i + 1 ].t - _sygnal.probki[ i ].t;
            dpole =( _sygnal.probki[ i ].x + _sygnal.probki[ i + 1 ].x ) * dt / 2;
            calka = calka + dpole;
        }
        return calka;
    }
};

#endif

Oraz plik z klasą SygnalLoader:
C/C++
#ifndef _SygnalLoader_h_
#define _SygnalLoader_h_
#include <string>
#include <fstream>
#include <sstream>
#include "Sygnal.h"
using namespace std;
class SygnalLoader
{
public:
    SygnalLoader() { }
    Sygnal wczytajSygnal( string _nazwaPliku )
    {
        /*typedef vector <Probka> Probki;
        ifstream plik;
        plik.open(_nazwaPliku.c_str(), ios::in);
        string linia;
        while (getline (plik, linia))
        {
        stringstream ss (linia);
        double liczba1, liczba2;
        ss >> liczba1;
        ss.ignore();
        ss >> liczba2;
        Probka nowa_probka = Probka(10,21);
        Sygnal x;
        x.dodajProbke(nowa_probka);
        }
        plik.close();*/
    }
    void zapiszSygnal( Sygnal & aSygnal, std::string aNazwaPliku );
};
#endif

Main ( do przetestowania działania ):
C/C++
#include <iostream>
#include "AnalizatorSygnalu.h"
#include "Sygnal.h"
#include "Probka.h"
#include "SygnalLoader.h"
using namespace std;

int main()
{
    SygnalLoader sl;
    AnalizatorSygnalu as;
    Sygnal s;
    Probka p = Probka( 10, 20 );
    s.dodajProbke( p ); // pierwsza probka
    Probka p2 = Probka( 20, 30 );
    s.dodajProbke( p2 ); // druga probka
    cout << "iloscProbek: " << s.iloscProbek() << endl;
    cout << "maksimum: " << as.maksimum( s ) << endl;
    cout << "minimum: " << as.minimum( s ) << endl;
    cout << "srednia: " << as.srednia( s ) << endl;
    cout << "dlugosc: " << as.dlugosc( s ) << endl;
    cout << "calka: " << as.calka( s ) << endl;
}

Po uruchomieniu programu main wyskakują, niedziwiące mnie zresztą błędy wskazujące na to, że wektor jest prywatny biorące się z klasy AnalizatorSygnalu ale zapewne także brałoby się z klasy SygnalLoader która służy do wczytania sygnału z pliku - fragment programu został wykomentowany bo sprawiał jakieś małe problemy. Dodałbym do funkcji Sygnal klasę zaprzyjaźnioną AnalizatorSygnalu, ale niestety prowadzący powiedział, tu cytuję: "Nie ma takiego elementu na schemacie UML więc proszę to usunąć". Jak więc mogę dostać się do tego elementu nie działając na więziach pomiędzy klasami? Jak pobrać zawartość wektora, jak coś do niego wpisać. Liczę na pomoc.

Jeżeli potrzeba więcej informacji na temat ww. dostarczę jak najszybciej.

Pozdrawiam.
P-166298
pekfos
» 2017-10-31 22:12:59
Po co ci dostęp do tego wektora? Nie wystarczą metody z klasy Sygnal?
P-166300
YooSy
» 2017-10-31 22:17:24
np. tak:
double _min = _sygnal[ 0 ].x;
, ale do tego musi być zdefiniowany
C/C++
Probka & operator []( int i ) { return probki[ i ]; }
const Probka & operator []( int i ) const { return probki[ i ]; }

Ogólnie kod jest do poprawienia.
Użycie przestrzeni nazw std w pliku nagłówkowym to zła praktyka.
Dodawanie podkreślenia przed nazwą zmiennej to zły nawyk.
Stosuj się do zasady The rule of three/five/zero
P-166302
selveee
Temat założony przez niniejszego użytkownika
» 2017-10-31 22:43:56
@pekfos
W teorii wystarczyłyby mi metody z klasy Sygnal, w praktyce jednak nie widzę, swoim okiem przynajmniej, bo dla klasy AnalizatorSygnalu nie widzę sposobu aby pobrać elementy z wektora chyba, że robiąc coś w stylu podpowiedzi kolegi @YooSy.

@YooSy
Co do definiowania operatorów, mam twardo zapisaną w schemacie UML ilość elementów, tj. funkcje, operatory i inne pierdółki, a jeżeli mi się dobrze wydaje to jeden z operatorów ( const ) jest dodany już od Ciebie a nie jest zawarty w schemacie - prowadzący bije po łapach jak próbujemy coś dodać, chyba że zawiera się wewnątrz elementu :(.

Dodałem przestrzeń nazw z przyzwyczajenia, pierwotnie było bez tego ale przepisywałem kod na nowo i dodałem żeby było szybciej, _ używam z przyzwyczajenia, możliwe że niesłusznie ale przynajmniej wiem co gdzie i jak.

P-166303
selveee
Temat założony przez niniejszego użytkownika
» 2017-10-31 23:16:06
Dziękuję Panowie ( i Panie ? ) za podrzucenie wręcz gotowego rozwiązania, działać działa jak należy, mam jednak pytanie co do jeszcze jednej klasy - mianowicie SygnalLoader, Sposób przedstawiony powyżej jest nieprawidłowy, tj. nie działa poprawnie, wysypuje program, robi różne cuda. Co trzeba tam poprawić, dodać, odjąć żeby nie sypał całego programu ( dodam że dane są w formie xxx, xxx gdzie xxx to liczby i jest ich 100 rekordów ) oraz jak sprawić aby dane zapisały się do wektora tego samego na którym będę później operował. W przypadku gdyby funkcja miała formę w stylu Sygnal wczytajSygnal(Sygnal& aSygnal, string _nazwaPliku) to nie byłoby problemu, tutaj jednak coś takiego nie występuje, jakieś pomysły ?

WIem, że może niejasno się wyrażam ale staram się przekazać co mam w swojej głowie jasno i zrozumiale :/
P-166306
YooSy
» 2017-10-31 23:41:15
WIem, że może niejasno się wyrażam ale staram się przekazać co mam w swojej głowie jasno i zrozumiale :/
Jaśniej i zrozumialej będzie jeśli powiesz co i w jaki sposób się "sypie".
Czy są to jakieś wyjątki, komunikaty systemowe, nieprawidłowe działanie, dane wyjściowe niezgodne z oczekiwanymi (mile widziane przykłady).

Pierwszym razem dokładnie był wskazany problem i został rozwiązany.

C/C++
Sygnal x;
x.dodajProbke( nowa_probka );
W każdej iteracji tworzysz nowy obiekt klasy Sygnal, zapisujesz dane i tracisz.
Zdefiniuj obiekt przed pętlą.
Nic nie zwracasz z metody wczytajSygnal choć deklarujesz, że zwrócisz.

Poza tym mocno komplikujesz sobie sprawę. stringstreamy nie są ci potrzebne.
C/C++
Sygnal sygnal;
double liczba1, liczba2;
char ignorowany_znak;
while( plik >> liczba >> ignorowany_znak >> liczba2 )
{
    sygnal.dodajProbke( Probka { liczba1, liczba2 } );
}
Coś takiego.
P-166308
selveee
Temat założony przez niniejszego użytkownika
» 2017-10-31 23:45:13
Nie potrafię tego przedstawić ze strony kompilatora, gdyż nie wysypuje mi żadnych widzialnych błędów ( tak używam Dev-Cpp i wszelakie debugery są mi obce, nie korzystałem nigdy ), zwyczajnie po uruchomieniu programu, dla przykładu:

Z klasy SygnalLoader ( mowa o funkcji wczytajSygnal ):
C/C++
#ifndef _SygnalLoader_h_
#define _SygnalLoader_h_
#include <string>
#include <fstream>
#include <sstream>
#include "Sygnal.h"
using namespace std;
class SygnalLoader
{
public:
    SygnalLoader() { }
    Sygnal wczytajSygnal( string _nazwaPliku )
    {
        Probka nowa_probka = Probka( 10, 21 );
        Sygnal s;
        s.dodajProbke( nowa_probka );
    }
    void zapiszSygnal( Sygnal & _Sygnal, std::string _nazwaPliku );
};
#endif

Oraz z main:
C/C++
#include <iostream>
#include "AnalizatorSygnalu.h"
#include "Sygnal.h"
#include "Probka.h"
#include "SygnalLoader.h"
using namespace std;

int main()
{
    SygnalLoader sl;
    AnalizatorSygnalu as;
    Sygnal s;
    Probka p = Probka( 10, 20 );
    s.dodajProbke( p ); // pierwsza probka
    Probka p2 = Probka( 20, 30 );
    s.dodajProbke( p2 ); // druga probka
    sl.wczytajSygnal( "sygnal.csv" ); // < -----------------
    //cout << "iloscProbek: " << s.iloscProbek() << endl;
    //cout << "maksimum: " <<as.maksimum(s) << endl;
    //cout << "minimum: " <<as.minimum(s) << endl;
    //cout << "srednia: " <<as.srednia(s) << endl;
    //cout << "dlugosc: " <<as.dlugosc(s) << endl;
    //cout << "calka: " <<as.calka(s) << endl;
}

Program najzwyczajniej w świecie myśli 1 - 2 sekundy po czym wypluwa komunikat że przestał działać. Drugi problem to to, że potrzebuję zastosować to tak, aby przy utworzeniu obiektu s klasy Sygnal móc wczytać elementy z wektora do którego zostały wpisane dane poprzez wczytanie funkcją wczytajSygnal - tak jak wspomniałem, gdyby funkcja przybrała formę
Sygnal wczytajSygnal( Sygnal & _sygnal, string _nazwaPliku )
 nie byłoby problemu, jednak tutaj przesłać do funkcji obiektu klasy nie mogę.

Może teraz coś więcej to opowie :)
P-166309
YooSy
» 2017-10-31 23:56:21
W poprzednim poście dopisałem kilka uwag.

Tutaj znalazłem kilka sposobów debugowania, gdy nie zna się swojego debuggera lub nie ma do niego dostępu.
https://www.youtube.com/watch​?v=FqKjc_VKPCk

Program najzwyczajniej w świecie myśli 1 - 2 sekundy po czym wypluwa komunikat że przestał działać.
Program w tym momencie ma niezdefiniowane zachowanie i może zachować się w dowolny sposób.
P-166310
« 1 » 2
  Strona 1 z 2 Następna strona