[SOLVED]Pointer class problem



  • Hi all

    I am busy with a QT exercise where I have to write a console app, impliment an asset class and three types of asset classes(bond, saving and stock) that inherits from Asset. I also have to impliment a class called assetList which derives from QList and only contains pointers to assets as elements. I'm not sure at all how to go about the assetList class. In the addAsset function how could I loop through the list using a foreach loop without having a name for the list? Could I use this? i'm also not sure if my constructor is ok. In the UML diagram the constructor doesn't have any parameters which confuses me a bit...

    my code:

    @
    Asset.h

    #ifndef ASSET_H
    #define ASSET_H
    #include <QString>
    #include <QDate>

    class Asset {
    public:
    Asset(QString des, QDate dat);
    virtual double value() = 0;
    QString getDescription() const;
    QString getType() const;
    protected:
    QString type;
    QDate date;
    private:
    QString description;
    };

    #endif // ASSET_H

    asset.cpp

    #include <QString>
    #include "Asset.h"

    Asset::Asset(QString des, QDate dat) {}

    //double Asset::value(){
    //return value;
    //}

    QString Asset::getDescription() const {
    return QString("%1").arg(description);
    }

    QString Asset::getType() const {
    return QString("%1").arg(type);
    }

    assetList.h

    #ifndef ASSETLIST_H
    #define ASSETLIST_H

    #include <QList>
    #include "Asset.h"
    class AssetList : public QList<Asset*>
    {
    Q_OBJECT
    public:
    explicit AssetList();
    ~AssetList();
    bool addAsset(Asset* a);
    Asset* findAsset(QString des);
    double totalValue(QString typ);

    signals:

    public slots:

    };

    #endif // ASSETLIST_H

    assetList.cpp

    #include "AssetList.h"
    #include "Asset.h"

    AssetList::AssetList() {
    QList<Asset*> list;
    }

    AssetList::~AssetList(){
    qDeleteAll(*this);
    clear();
    }

    bool AssetList::addAsset(Asset *a){
    bool duplicateAsset = false;

    foreach(asset* b, this) {
        if (b->getDescription() == a->getDescription())
            duplicateAsset = true;
    }
        if (duplicateAsset == true) {
                cout << "Unable to add duplicate asset to list ";
                break;
                }
        else:
                list.append(a);
        }
    

    Asset* AssetList::findAsset(QString des) {
    asset* searchItem;

        foreach(asset* b, list) {
        if (b->getDescription() == des)
            searchItem = b;
        else
            searchItem = 0;
    }
    
    return searchItem;
    

    }

    double AssetList::totalValue(QString typ){
    double totalValue = 0;

    foreach(asset* b, list) {
        if (b->getType() == typ)
            totalValue += b->value();
    }
    
    return totalValue;
    

    }

    bond.h

    #ifndef BOND_H
    #define BOND_H
    #include "Asset.h"

    class Bond : public Asset
    {
    public:
    Bond(QString des, QDate dat, double fva, double yie);
    double value();
    private:
    double faceValue;
    double yield;
    };

    #endif // BOND_H

    bond.cpp

    #include "Bond.h"

    Bond::Bond(QString des, QDate dat, double fva, double yie)
    : Asset(des, dat), faceValue(fva), yield(yie)
    {
    }

    double Bond::value() {
    QDate tempDate;
    tempDate.currentDate();
    double interestEarned = tempDate.year() - date.year();
    double totalEarned = interestEarned * faceValue;
    return totalEarned;
    }

    Stock.h
    #ifndef STOCK_H
    #define STOCK_H
    #include <QString>
    #include "Asset.h"

    class Stock: public Asset {
    public:
    Stock(QString des, QDate dat, int nsh, double spr);
    double value();
    double setPrice(double np);
    private:
    int numShares;
    double sharePrice;

    };

    #endif // STOCK_H

    Stock.cpp

    #ifndef STOCK_H
    #define STOCK_H
    #include <QString>
    #include "Asset.h"

    class Stock: public Asset {
    public:
    Stock(QString des, QDate dat, int nsh, double spr);
    double value();
    double setPrice(double np);
    private:
    int numShares;
    double sharePrice;

    };

    #endif // STOCK_H

    saving.h
    #ifndef SAVING_H
    #define SAVING_H
    #include "Asset.h"

    class Saving : public Asset
    {
    public:
    Saving(QString des, QDate dat, double cva, double ira); //Saving constructor
    double value();
    double changeValue(double amount);
    void addInterest();
    private:
    double currentValue;
    double interestRate;
    };

    #endif // SAVING_H

    saving.cpp

    #include <QString>
    #include <QDate>
    #include "saving.h"

    Saving::Saving(QString des, QDate dat, double cva, double ira)
    : Asset(des, date), currentValue(cva), interestRate(ira) {
    }

    double Saving::value() {
    return currentValue;
    }

    double Saving::changeValue(double amount) {
    if (amount >= 0)
    currentValue += amount;
    else
    currentValue -= amount;
    return currentValue;
    }

    void Saving::addInterest() {
    currentValue += ((currentValue / 100) * (interestRate / 12));
    }

    main.cpp

    #include <QString>
    #include <QTextStream>
    #include <QDate>
    #include "Stock.h"
    #include "Bond.h"
    #include "AssetList.h"

    QTextStream cin(stdin);
    QTextStream cout(stdout);

    int main() {
    QString type, dat, des;
    QDate date;
    int numShares;
    double sharePrice, faceValue, yield;

    cout << "Enter Asset type: ";
    cin >> type;
    cout << "Enter description: ";
    cin >> des;
    cout << "Enter date YY/MM/DD";
    cin >> dat;
    date.fromString(dat);
    
    if (type == "Stock" || type == "stock" || type == "STOCK") {
    
        cout << "Enter number of shares ";
        cin >> numShares;
        cout << "Enter the sharePrice ";
        cin >> sharePrice;
        Stock(des, date, numShares, sharePrice);
    }
    else if (type == "Bond" || type == "bond" || type == "BOND") {
        cout << "Enter face balue: ";
        cin >> faceValue;
        cout << "Enter yield: ";
        cin >> yield;
        Bond(des, date, faceValue, yield);
    }
    
    return 0;
    

    }
    @


  • Lifetime Qt Champion

    Hi,

    You AssetList class is not correct. You are deriving from QList which destructor is not virtual so your destructor won't be called. Also you have a QList member in your QList derived class which doesn't make sense.

    So now the design question is: do you need a class that encapsulate a list or a list class ?



  • Personally, I prefer for-range loops over for_each. So my implementation would look something like the following:

    @
    bool AssetList::addAsset(const Asset* asset)
    {
    auto duplicateAsset = false;

     for(const auto& assetChild : *this)
     {
          if(assetChild->getDescription() == asset->getDescription())
          {
               duplicateAsset = true;
               break;
          }
     }
    
     if(duplicateAsset == true)
     {
          cout << "error message" << endl;
     }
     else
     {
          this->push_back(asset);
     }
    

    }
    @

    Something like the above would be what I'd attempt.
    If you must use std::for_each():

    @

    std::for_each(std::begin(*this), std::end(this),
    [asset, duplicateAsset](const Asset
    childAsset)
    {
    if(childAsset->getDescription() == asset->getDescription()
    {
    duplicateAsset = true;
    }
    });

    // do work

    @

    As you can see, std::for_each gets a little more complicated and the above example would be using lambda functions.

    I think the for-range loop is much easier to read and understand.

    Hope this helps



  • Hi

    Which member doesn't make sense? Also if I implement it with the for loop what does assetChild refer to? So in the totalValue function I could also use "*this" to loop through the same list?



  • First off, SGaist is correct, Im still new to Qt, isn't realize you couldn't inherit QList. You need to get rid of the inheritance and keep the list member variable.

    childAsset refers to a child object in the list. The for loop iterates through each item in the list and is called childAsset. Read up on range based for loops.


  • Lifetime Qt Champion

    I didn't say that you can't do that. You can inherit QList (take for example QQueue) It's just that there are some limitation on what you can do.

    Since AssetList is a QList, why does it contain a QList member variable ?



  • In the for loop is assetChild of type assetList? I tried using auto but keep getting the error message auto will change the meaning of *this please remove it



  • or could I do something like this?

    for (int i = 0; i <= this->size() ++i)



  • That is a c++11 range-based for loop, (just google it), and the meaning of "auto" has also changed with c++11 so it depends on your compiler or the compiler flags if you can use that or not. With a qmake based project you can just use this in your project file:
    @
    CONFIG += c++11
    @
    In your case using "auto" type inference doesn't make much sense, so you can just use the correct types since there aren't that complicated I guess (who uses "auto b = false" anyways haha).

    so instead of
    @
    for(const auto& assetChild : *this)
    @
    you can just write
    @
    for(const Asset *assetChild : *this)
    @
    or Qt foreach style (works without any c++11 compiler features)
    @
    foreach(const Asset *assetChild, *this)
    @

    if you want use a default for loop, but I think it's more readable like this.



  • Thanks Xander. I managed to get it working with a for loop using this->at() to check the current value...


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.