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

C++ przeciążenie operatora<< klasy

Ostatnio zmodyfikowano 2018-07-18 21:35
Autor Wiadomość
Kefirek
Temat założony przez niniejszego użytkownika
C++ przeciążenie operatora<< klasy
» 2018-07-18 11:12:57
Witam
Klasa Magazyn zawiera składową prywatną Towar *ctowar(wskaźnik do klasy Towar).
Klasa Towar posiada zaprzyjaźnioną funkcję przeciążającą operator<< do przekazania swoich składowych do strumienia(patrz. poniżej kod klasy Towar.h, Towar.cpp)

Klasa Magazyn posiada funkcję zaprzyjaźnioną przeciążającą operator<< do przekazania swoich składowych do strumienia(patrz. poniżej kod klasy Magazyn.h, Magazyn.cpp).

W ciele funkcji wyrażenie magazyn.GetTowar() :
C/C++
QDataStream & operator <<( QDataStream & out, const Magazyn & magazyn )
{
    out << magazyn.GetNazwa() << magazyn.GetTowar();
    return out;
}
powoduje błąd przy próbie zapisu danych do pliku.

Mógłbym zapisać magazyn.GetTowar().GetGoodsCateory() << itd następne składowe i to działa.

Moje pytanie dlaczego nie zadziała ...<< magazyn.GetTowar(); z powyższej funkcji
skoro W klasie Towar jest zdefiniowany operator<< ??? :

C/C++
QDataStream & operator <<( QDataStream & out, const Towar & towar )
{
    out << towar.cGoodsCategory << towar.cGoodsSubCategory << towar.cProducer << towar.cGoodsUse << towar.cTradeName << towar.cPrice << towar.cCurrency
    << towar.cUnitQuantities << towar.GetGabaryt();
    return out;
}

i wie jak przekazać składowe klasy Towar do strumienia.

Jak uniknąć ponownego wypisywania wszystkich składowych w funkcji:

C/C++
QDataStream & operator <<( QDataStream & out, const Magazyn & magazyn )
{
    out << magazyn.GetNazwa() << magazyn.GetTowar().GetGoodsCategory() //itd następne składowe;
    return out;
}



Klasa Magazyn.h############################################################

C/C++
#ifndef MAGAZYN_H
#define MAGAZYN_H

#include <QString>
#include "domlibcore_global.h"
#include <Towar.h>
#include <QVector>

class Towar;

class DOMLIBCORESHARED_EXPORT Magazyn
{
public:
    Magazyn( QString nazwaMagazyn, Towar * towar );
    Magazyn();
    virtual ~Magazyn();
   
    void SetNazwa( QString nazwaMagazyn );
    void SetTowar( Towar * towar );
   
    QString GetNazwa() const;
    Towar & GetTowar() const;
   
    friend QDataStream & operator <<( QDataStream & out, const Magazyn & magazyn );
    friend QDataStream & operator >>( QDataStream & in, Magazyn & magazyn );
   
private:
   
    QString cNazwaMagazyn;
    Towar * cTowar;
   
};

#endif // MAGAZYN_H

Klasa Magazyn.cpp############################################################

C/C++
#include "magazyn.h"

Magazyn::Magazyn( QString nazwaMagazyn, Towar * towar )
    : cNazwaMagazyn( nazwaMagazyn )
     , cTowar( towar )
{
}

Magazyn::Magazyn()
{
}

Magazyn::~Magazyn()
{
}

void Magazyn::SetNazwa( QString nazwaMagazyn )
{
    cNazwaMagazyn = nazwaMagazyn;
}

void Magazyn::SetTowar( Towar * towar )
{
    cTowar = towar;
}

QString Magazyn::GetNazwa() const
{
    return cNazwaMagazyn;
}

Towar & Magazyn::GetTowar() const
{
    return * cTowar;
}

QDataStream & operator <<( QDataStream & out, const Magazyn & magazyn )
{
    out << magazyn.GetNazwa() << magazyn.GetTowar();
    return out;
}
QDataStream & operator >>( QDataStream & in, Magazyn & magazyn )
{
    in >> magazyn.cNazwaMagazyn >> magazyn.GetTowar();
    return in;
}

Klasa Towar.h############################################################

C/C++
#ifndef TOWAR_H
#define TOWAR_H

#include <QString>
#include <QDate>
#include <gabaryt.h>
#include "domlibcore_global.h"

class Gabaryt;

class DOMLIBCORESHARED_EXPORT Towar
{
   
public:
    Towar( QString goodsCategory, QString goodsSubCategory, QString producer, QString goodsUse, QString tradeName,
    double prise, int quantity, double vlaue, QString currency, QString unitQuantities, Gabaryt * gabaryt );
    Towar();
    virtual ~Towar();
   
   
    void SetGoodsCategory( QString goodsCategory );
    void SetGoodsSubCategory( QString goodsSubCategory );
    void SetProducer( QString producer );
    void SetGoodsUse( QString goodsUse );
    void SetTradeName( QString tradeName );
    void SetPrise( double prise );
    void SetQuantity( int quantity );
    void SetCurrency( QString currency );
    void SetUnitQuantities( QString unitQuantities );
   
    QString GetGoodsCategory() const;
    QString GetGoodsSubCategory() const;
    QString GetProducer() const;
    QString GetGoodsUse() const;
    QString GetTradeName() const;
    double GetPrise() const;
    int GetQuantity() const;
    double GetValue() const;
    QString GetCurrency() const;
    QString GetUnitQuantities() const;
    Gabaryt & GetGabaryt() const;
   
private:
    QString cGoodsCategory; //kategoria towaru np budowlane
    QString cGoodsSubCategory; //podkategoria towaru np zaprawy klejowe
    QString cProducer; //producent
    QString cGoodsUse; //jak będzie wykorzystane
    QString cTradeName; //nazwa handlowa
    double cPrice;
    int cQuantity;
    double Cvalue;
    QString cCurrency; //pln, nok
    QString cUnitQuantities; //szt, kg   
    Gabaryt * cGabaryt; //wymiary przedmiotu;
   
};

#endif // TOWAR_H

Klasa Towar.cpp############################################################

C/C++
#include "towar.h"


Towar::Towar( QString goodsCategory, QString goodsSubCategory, QString producer, QString goodsUse, QString tradeName,
double prise, int quantity, double value, QString currency, QString unitQuantities, Gabaryt * gabaryt )
    : cGoodsCategory( goodsCategory )
     , cGoodsSubCategory( goodsSubCategory )
     , cProducer( producer )
     , cGoodsUse( goodsUse )
     , cTradeName( tradeName )
     , cPrice( prise )
     , cQuantity( quantity )
     , Cvalue( value )
     , cCurrency( currency )
     , cUnitQuantities( unitQuantities )
     , cGabaryt( gabaryt )
{
}
Towar::Towar()
{
}

Towar::~Towar()
{
}

void Towar::SetGoodsCategory( QString goodsCategory )
{
    cGoodsCategory = goodsCategory;
}

void Towar::SetGoodsSubCategory( QString goodsSubCategory )
{
    cGoodsSubCategory = goodsSubCategory;
}

void Towar::SetProducer( QString producer )
{
    cProducer = producer;
}

void Towar::SetGoodsUse( QString goodsUse )
{
    cGoodsUse = goodsUse;
}

void Towar::SetTradeName( QString tradeName )
{
    cTradeName = tradeName;
}

void Towar::SetPrise( double prise )
{
    cPrice = prise;
}

void Towar::SetQuantity( int quantity )
{
    cQuantity = quantity;
}

void Towar::SetCurrency( QString currency )
{
    cCurrency = currency;
}

void Towar::SetUnitQuantities( QString unitQuantities )
{
    cUnitQuantities = unitQuantities;
}

QString Towar::GetGoodsCategory() const
{
    return cGoodsCategory;
}

QString Towar::GetGoodsSubCategory() const
{
    return cGoodsSubCategory;
}

QString Towar::GetProducer() const
{
    return cProducer;
}

QString Towar::GetGoodsUse() const
{
    return cGoodsUse;
}

QString Towar::GetTradeName() const
{
    return cTradeName;
}

double Towar::GetPrise() const
{
    return cPrice;
}

int Towar::GetQuantity() const
{
    return cQuantity;
}

double Towar::GetValue() const
{
    return cQuantity * cPrice;
}

QString Towar::GetCurrency() const
{
    return cCurrency;
}

QString Towar::GetUnitQuantities() const
{
    return cUnitQuantities;
}

Gabaryt & Towar::GetGabaryt() const
{
    return * cGabaryt;
}

QDataStream & operator <<( QDataStream & out, const Towar & towar )
{
    out << towar.cGoodsCategory << towar.cGoodsSubCategory << towar.cProducer << towar.cGoodsUse << towar.cTradeName << towar.cPrice << towar.cCurrency
    << towar.cUnitQuantities << towar.GetGabaryt();
    return out;
}
QDataStream & operator >>( QDataStream & in, Towar & towar )
{
    in >> towar.cGoodsCategory >> towar.cGoodsSubCategory >> towar.cProducer >> towar.cGoodsUse >> towar.cTradeName >> towar.cPrice >> towar.cCurrency
    >> towar.cUnitQuantities >> towar.GetGabaryt();
    return in;
}
Pozdrawiam
P-171900
pekfos
» 2018-07-18 13:18:36
Jaki błąd?
P-171901
Kefirek
Temat założony przez niniejszego użytkownika
Odp
» 2018-07-18 15:25:09
Program przerywał działanie po próbie zapisu danych klas do pliku binarnego: program nieoczekiwanie przerwał działanie.
Poniżej funkcja zapisująca dane klas do pliku binarnego:
C/C++
bool MagazynDao::CreateMagazyn( Magazyn & magazyn ) //same stworzenie pliku o nazwie magazynu
{
    CreateMagazynDirectory();
   
    //tu utworzenie pliku o nazwie magazynu
    QString fileName = magazyn.GetNazwa() + ".mag";
    QFile file( "./Magazins/" + fileName ); //... jesli nie tworzymy
    if( !file.open( QIODevice::WriteOnly | QIODevice::Append ) )
         return false;
   
    QDataStream out( & file );
    out.setVersion( QDataStream::Qt_5_10 );
    out << magazyn;
   
    file.close();
    return true;
}
Poniżej funkcja inicjacyjna danych składowych klas - już poprawiona druga wersja z którą program działa prawidłowo:
C/C++
QStringListModel & MagazynModel::CreateMagazyn()
{
    cListaMagazyn.append( cModelName );
    cListModelMagazyn->setStringList( cListaMagazyn );
   
    qDebug() << cListaMagazyn.size() << " - Model name: " << cModelName;
   
    Gabaryt * gabaryt = new Gabaryt( 5, 6, 6, "ddd", "m" );
    Towar * towar = new Towar( "d", "c", "S", "e", "d", 5, 5, 6, "p", "d", gabaryt );
    Magazyn * magazyn = new Magazyn( cModelName, towar );
   
    qDebug() << "True or False: " << magazynDao.CreateMagazyn( * magazyn );
   
    return * cListModelMagazyn;
}

Wcześniej wyglądało to tak - wersja z którą program kończył nieoczekiwanie działanie:

C/C++
QStringListModel & MagazynModel::CreateMagazyn()
{
    cListaMagazyn.append( cModelName );
    cListModelMagazyn->setStringList( cListaMagazyn );
   
    qDebug() << cListaMagazyn.size() << " - Model name: " << cModelName;
   
    Gabaryt * gabaryt = new Gabaryt(); //: błąd: call of overloaded 'Gabaryt()' is ambiguous
    //poniżej Settery
    gabaryt->SetLenght();
    //itd...
   
    Towar * towar = new Towar();
    towar->SetGoodsUse();
    //itd..
    towar->SetGabaryt( gabaryt );
   
    Magazyn * magazyn = new Magazyn();
    magazyn->SetNazwe();
    magazyn->SetTowar( towar );
   
   
    qDebug() << "True or False: " << magazynDao.CreateMagazyn( * magazyn );
   
    return * cListModelMagazyn;
Czyli wywołanie konstruktorów bezparametrowych dla poszczególnych klas i ustawienie składowych klas Setter'ami
Nie wiadomo dlaczego nie mogłem wywołać konstruktora bezparametrowego dla klasy Gabaryt. Po jego wykomentowaniu
udało się zapisać do pliku jedynie nazwę magazynu: magazyn->SetNazwe(cMagazynName);
bład:
call of overloaded 'Gabaryt()' is ambiguous. Klasa Gabaryt poniżej:

Klasa Gabaryt.h
C/C++
ifndef GABARYT_H
#define GABARYT_H

#include <QString>
#include "domlibcore_global.h"
#include <QDataStream>

class DOMLIBCORESHARED_EXPORT Gabaryt
{
public:
    Gabaryt( double width = 0, double height = 0, double depth = 0, QString volumeUnit = "m3", QString linearUnit = "m" );
    Gabaryt();
    virtual ~Gabaryt();
   
    void SetWidth( double width );
    void SetHeight( double height );
    void SetDepht( double depth );
    void SetVolumeUnit( QString volumeUnit );
    void SetLinearUnit( QString linearUnit );
   
    double GetWidth() const;
    double GetHeight() const;
    double GetDepth() const;
    QString GetVolumeUnit() const;
    QString GetLinearUnit() const;
    double GetVolume() const;
   
    friend QDataStream & operator <<( QDataStream & out, const Gabaryt & gabaryt );
    friend QDataStream & operator >>( QDataStream & in, Gabaryt & gabaryt );
   
private:
    double cWidth;
    double cHeight;
    double cDepth;
    double cVolume;
    QString cVolumeUnit;
    QString cLienarUnit;
   
   
};

#endif // GABARYT_H
Klasa Gabaryt.cpp

C/C++
#include "gabaryt.h"
#include <cstring>

Gabaryt::Gabaryt( double width, double height, double depth, QString volumeUnit, QString linearUnit )
    : cWidth( width )
     , cHeight( height )
     , cDepth( depth )
     , cVolumeUnit( volumeUnit )
     , cLienarUnit( linearUnit )
{
}

Gabaryt::Gabaryt()
{
}

Gabaryt::~Gabaryt()
{
}

void Gabaryt::SetWidth( double width )
{
    cWidth = width;
}

void Gabaryt::SetHeight( double height )
{
    cHeight = height;
}

void Gabaryt::SetDepht( double depth )
{
    cDepth = depth;
}

void Gabaryt::SetVolumeUnit( QString volumeUnit )
{
    cVolumeUnit = volumeUnit;
}

void Gabaryt::SetLinearUnit( QString linearUnit )
{
    cLienarUnit = linearUnit;
}

double Gabaryt::GetWidth() const
{
    return cWidth;
}

double Gabaryt::GetHeight() const
{
    return cHeight;
}

double Gabaryt::GetDepth() const
{
    return cDepth;
}

QString Gabaryt::GetVolumeUnit() const
{
    return cVolumeUnit;
}

QString Gabaryt::GetLinearUnit() const
{
    return cLienarUnit;
}

double Gabaryt::GetVolume() const
{
    return cWidth * cHeight * cDepth;
}

QDataStream & operator <<( QDataStream & out, const Gabaryt & gabaryt )
{
    out << gabaryt.cWidth << gabaryt.cHeight << gabaryt.cDepth << gabaryt.cVolumeUnit << gabaryt.cLienarUnit;
    return out;
}
QDataStream & operator >>( QDataStream & in, Gabaryt & gabaryt )
{
    in >> gabaryt.cWidth >> gabaryt.cHeight >> gabaryt.cDepth >> gabaryt.cVolumeUnit >> gabaryt.cLienarUnit;
    return in;
}
Wyglada to tak jakby tylko wywołanie konstruktorów z parametrami było prawidłowe, a wywołanie konstruktorów
bezparametrowych i następnie ustawianie składowych klas settr'ami nie było w tym wypadku prawidłowe??????
O co chodzi?????
P-171904
Kefirek
Temat założony przez niniejszego użytkownika
cd...
» 2018-07-18 17:04:19
Po pozbyciu się parametrów domyślnych w konstruktorze Klasy Gabaryt:
Było:
C/C++
Gabaryt::Gabaryt( double width = 0, double height = 0, double depth = 0, QString volumeUnit = "mm3", QString linearUnit = "mm" )
    : cWidth( width )
     , cHeight( height )
     , cDepth( depth )
     , cVolumeUnit( volumeUnit )
     , cLienarUnit( linearUnit )
{
   
}

Jest:
C/C++
Gabaryt::Gabaryt( double width, double height, double depth, QString volumeUnit, QString linearUnit )
    : cWidth( width )
     , cHeight( height )
     , cDepth( depth )
     , cVolumeUnit( volumeUnit )
     , cLienarUnit( linearUnit )
{
   
}

...nie wywala już błedu przy wywoływaniu konstruktora bezparametrowego klasy Gabaryt()
Gabaryt *gabaryt = new Gabaryt() - teraz ok i wszystko się kompiluje i prawidłowo zapisuje do pliku korzystając
z konstruktorów domyślnych jak poniżej:

C/C++
QStringListModel & MagazynModel::CreateMagazyn()
{
    cListaMagazyn.append( cModelName );
    cListModelMagazyn->setStringList( cListaMagazyn );
   
    Gabaryt * gab = new Gabaryt();
    gab->SetDepht( 5 ); gab->SetHeight( 5 ); gab->SetLinearUnit( "mm" ); gab->SetVolumeUnit( "mm3" );
    gab->SetWidth( 6 );
    Towar * towar = new Towar();
    towar->SetCurrency( "pln" ); towar->SetGabaryt( gab ); towar->SetGoodsCategory( "kk" ); towar->SetGoodsSubCategory( "k" );
    towar->SetGoodsUse( "kk" ); towar->SetPrise( 5 ); towar->SetProducer( "kk" ); towar->SetQuantity( 3 );
    towar->SetTradeName( "ds" ); towar->SetUnitQuantities( "kl" ); towar->SetValue( 5 );
    Magazyn * magazyn = new Magazyn();
    magazyn->SetNazwa( cModelName );
    magazyn->SetTowar( towar );
   
    qDebug() << "True or False: " << magazynDao.CreateMagazyn( * magazyn );
}

Ciekawe dlaczego parametry domyślne w konstruktorze z parametrami powodowało nie możliwość użycia konstruktora
bezparametrowego klasy Gabaryt?????????
P-171905
j23
» 2018-07-18 20:03:10
Metoda Magazyn::GetTowar nie powinna zwracać referencji, jeśli jest możliwość ustawienia cTowar na nullptr. W domyślnym konstruktorze klasy Magazyn powinieneś ustawić cTowar na jakąś konkretną wartość.
P-171908
Kefirek
Temat założony przez niniejszego użytkownika
cd...
» 2018-07-18 20:47:32
Zgadzam się co do zwracanej referencji - moje przeoczenie :-) poprawione:
C/C++
Towar Magazyn::GetTowar() const
{
    return * cTowar;
}

Mogę ustawić cTowar w Magazyn.h
C/C++
//...cd Magazyn.h
private:

QString cNazwaMagazyn;
Towar * cTowar = nullptr;

[cyt]
W domyślnym konstruktorze klasy Magazyn powinieneś ustawić cTowar na jakąś konkretną wartość.
[/cyt]

C/C++
Magazyn::Magazyn()
{
    cTowar->cCurrency = "pln";
    cTowar->cGoodsCategory = "Budowlane";
    //itd
    cTowar->cGabaryt = ???? //cGabaryt to prywatna składowa klasy Towar można upublicznić???
}
P-171909
pekfos
» 2018-07-18 20:49:47
To nie jest poprawione.

C/C++
Magazyn::Magazyn()
{
    cTowar->cCurrency = "pln";
    cTowar->cGoodsCategory = "Budowlane";
    //itd
    cTowar->cGabaryt = ???? //cGabaryt to prywatna składowa klasy Towar można upublicznić???
}
A to są bzdury. Miałeś nadać jakąś wartość cTowar, czyli wskaźnikowi. Zamiast tego próbujesz duplikować funkcjonalność konstruktora Towar. Jeśli cTowar jest wskaźnikiem z jakiegoś powodu (innego niż 'bo tak ci się napisało'), to albo gwarantuj, że wskazuje na coś z sensem, albo uwzględniaj możliwość, że nie wskazuje na nic.
P-171910
Kefirek
Temat założony przez niniejszego użytkownika
cd...
» 2018-07-18 21:13:40
Zmieniłem wartość zwracaną z referencji
C/C++
Gabaryt & Towar::GetGabaryt() const;


//na

Gabaryt Towar::GetGabaryt() const;
 
ale wywala błąd: :160: błąd: no match for 'operator>>' (operand types are 'QDataStream' and 'Gabaryt')
        >> towar.cUnitQuantities >> towar.GetGabaryt();
                                 ^
błąd: invalid initialization of non-const reference of type 'Gabaryt&' from an rvalue of type 'Gabaryt'
        >> towar.cUnitQuantities >> towar.GetGabaryt();
                                                    ^
Ciekawe , że po analogicznej zmianie dla Klasy Magazyn powyższy błąd nie występuje.

Kod klas pisałem dość dawno, i przypominam sobie, że właśnie miałem problem z tym błędem i dlatego zwracałem przez referencje i wtedy kod się prawidłowo kompilował.????
P-171911
« 1 » 2
  Strona 1 z 2 Następna strona