PDA

View Full Version : QList of my own class (append)



april26
19th March 2011, 11:10
I have a Class "Transaction" with 3 members (Int, double, QDate). The instances are created using a constructor that provides the first two variables, and QDate is the current date.

The constructor is


Transaction::Transaction(int n, double p):
m_NoOfItems(n), m_PricePerItem(p), m_Transactions(QDate::currentDate())
{};


I have a Class Product which has a private member: QList<Transaction> m_Transactions. It is not a pointer class.

When products are sold the method sell(int n) is called, and it is meant to create a Transaction record and append it to the QList m_Transactions. I have tried for about 5 hours now and after trying many of the approaches offered by other forums I can't find a way to create a Transaction. Or possibly I am creating the transaction and each transaction is overwriting. I have been using the size of m_Transactions to judge whether the transaction is being stored, because I can't traverse the list either.


void Product::sell(int n) {
if (m_NoOfItems < n)
cout << "Transaction failed - insufficient stock" <<endl;
else {
m_NoOfItems -= n;
m_Transactions.append(Transaction(3,1.00));

cout <<"Size of array:" << m_Transactions.size() <<endl;
}

}


I am a beginner with both C++ and Qt and the reference material and error messages don't make much sense to me. I am working by trial and error (a great MANY errors). I can append, print and work perfectly with a QList <int> but not with my own class.

I am getting quite desperate, as once I get this to work I then have another QList of pointers which looks even worse! Please can anyone help?

Zlatomir
19th March 2011, 11:21
That code should work, what is the error message?

And be careful about containers of pointers if you allocate heap memory (use new) you need to manually delete the pointers in container before remove them (or before the container gets out of scope)

april26
19th March 2011, 11:36
Hi Zlatomir,

Thank you so much for helping. I don't get an error, but the size of the array remains 1. I can't check as I haven't found a way to print QList m_Transactions. Transactions has a method .toString() that I know works. I keep getting a new empty list.

Zlatomir
19th March 2011, 11:53
This code iterate over the QList and call the toString() member function:


for(QList<Transaction>::ConstIterator it = m_Transactions.begin(); it != m_Transactions.end(); ++it) {
std::cout << qPrintable(it->toString()); //i used qPrintable to be able to print QString to std::cout
}


LE: and about the problem if you sell many times, make sure you call sell for the same object, or you can post more code, because that append should work.

april26
19th March 2011, 12:49
Thank you that works. :-)

I must have a logic error. Main has several items being sold. My intention was to add each sale to the m_Transactions list - each product I sell adds to the array, so after the first sale it prints one line, after the second sale it prints two lines. Although this prints each sale, it doesn't appear to be storing the previous transactions. My third sale is "rejected" because insufficient items and it appears that m_Transactions array size is zero?

Added after 7 minutes:

(I have since fixed the transaction, which was showing number of items in stock not number of items sold)

This is main



#include <QString>
#include <QTextStream>
#include <QList>
#include "product.h"
#include "foodproduct.h"
#include "transaction.h"
#include <QDebug>


int main() {
QTextStream cout(stdout);

Product book1("The Hobbit",6,15,5.00);
Product book2("Lord of the Rings",1,10,7.00);
Product cd1("Genesis",1,2,3.00);
FoodProduct chocolate("Marsbar",5,100,5.75,QDate::currentDate());

book1.sell(5);
book2.sell(5);
cd1.sell(5);


return 0;
}



And this is the printout


Transaction Recorded: 10 items @ R5.00 on 19/03/2011
Size of array:1

Transaction Recorded: 5 items @ R7.00 on 19/03/2011
Size of array:1

Transaction failed - insufficient stock
Size of array:0

Press <RETURN> to close this window...

Added after 11 minutes:

Just curious - when I was trying to find a solution, many people seemed to have a simple "for int i etc" to traverse a QList. Obviously the ConstIterator is much better (and as I know the "int i" version doesn't work!) I assume I can use the same method for my pointer list should I ever get that far!

Does one use ConstIterator for all QLists? Are there times (and types of lists) where "For int i..." will work?

Added after 4 minutes:

Sorry, my function sell() now looks like this. I assume the error lies with the .append somehow?


void Product::sell(int n) {
if (m_NoOfItems < n)
cout << "Transaction failed - insufficient stock" <<endl;
else {
m_NoOfItems -= n;
m_Transactions.append(Transaction(n,m_PricePerItem ));
for(QList<Transaction>::ConstIterator it = m_Transactions.begin(); it != m_Transactions.end(); ++it) {
cout << it->toString(); //i used qPrintable to be able to print QString to std::cout
}
}
cout <<"Size of array:" << m_Transactions.size() <<endl;
}

Added after 21 minutes:

Actually, it does seem to be working just strangely.

I have now written the "RemoveAll() function" and both the original sale and the remove all are showing in transactions. As long as I only sell and remove a single product, the transactions are all listed to do with that one product. When I sell other products, they each have a transaction, but it appears to be in a separate array.

stampede
19th March 2011, 15:03
If you want to simply iterate and read values from list, I prefer foreach for this, code looks very simple:


foreach(const Transaction& t, m_Transactions ) {
cout << t.toString();
}

april26
19th March 2011, 15:08
How can so few letter take me so many hours :-( I think if I used a random letter/number generator it would probably code faster and more accurately than I do:)! At least Zlatomir's made me feel better because it LOOKS complicated :-)

I have begun on my ProductList which is a pointer QList - I have used the foreach for that, and it appears to be working? No-one is more surprised than me!

Zlatomir
19th March 2011, 15:48
There is no problem if the things looks complicated in the beginning, from the complicated things you learn and then you can use the simple ones ;) and in this case it works with list[i] with iterators and with algorithms (foreach) but you should know how each of containers work (like a QLinkedList<T> doesn't have the operator [])

And now about your problem, this comes from here:


Product book1("The Hobbit",6,15,5.00);
Product book2("Lord of the Rings",1,10,7.00);
Product cd1("Genesis",1,2,3.00);

Each Product has it's own (separate) list of sales (that list is a member in the class)

To solve this you can either:
1) (simple method) create a static list (to have one instance for all the Product objects
or
2) you can create a new class (for example Store) and that class can receive "merchandise" and sell it (and this class will keep a list of products in stock)

//the code works right now (mean that it is correct from compiler point of view), but this is simple a task for you to design the software (the logic flow) and decide how your objects will interact ;)

april26
19th March 2011, 15:52
Thank you, that makes sense.

I am currently working on the ProductList class which is a QList that has its own sell(int n), that calls product.sell(int n). Is this what you mean in Point 2?

Zlatomir
19th March 2011, 15:57
Also take care because i saw that you use classes derived from Product (or at least i assume that FoodProduct is derived), if you add one of those to the list that contains Product objects it gets "sliced" to Product (base class).

To correctly solve this polymorphic you need a container of pointers to Product and they can be assigned a pointer to derived class and work polymorphic.

LE: and don't forget if you use new-ed pointers in the list, you are responsible with delete it before you remove an pointer from the list, and all of them before the list gets out of scope.

april26
19th March 2011, 16:02
That is so far over my head, I barely heard it "whoosh" past.

What do you mean "sliced"?

This is my headerfile of the class QList of pointers to actual products.


#ifndef PRODUCTLIST_H
#define PRODUCTLIST_H


#include <QString>
#include <QDate>
#include <QList>


class Product;
class FoodProduct;

class ProductList : public QList<Product*>{
public:

int add(Product* p) ;
bool sell (int pc, int n) ;
bool remove(int pc) ;
bool deleteAll() ;

public:
bool codeUsed(int pc);
};

#endif // #ifndef PRODUCTLIST_H

FoodProduct is a derived class of Product. It has it's own sell(int n) function but all I did was run the base class one in it's code? I wasn't sure why it had it's own one.

Zlatomir
19th March 2011, 16:10
Don't derive from the containers, usually they are not designed to be base class (i'm not sure about Qt's containers, but the STL ones are not meant to be inherited), so don't do this:

class ProductList : public QList<Product*>{
Make a class, you can call it Store (or SuperMarket ;) ) and make the productList a member of that class (you can further model the receiving merchandise and selling it)

//By sliced i mean truncated, if FoodProduct has a new member (lets say nutrientValue) and the toString member function is used virtual and simply overridden to add to the returned QString the nutrientValue this works with pointers, but not with objects (with objects the FoodProduct will be cut and will be a simple Product)


LE: my bad, the List contains Transactions (which is not inherited) not Products, just remember what i said about this, you will eventually have something to do with the polymorphism ;)

april26
19th March 2011, 16:29
It works! OK, probably not absolutely everything, but it works in principle, I can add and sell products, the stock levels work. I allocated unique codes, it increments any code I provide until it's unique. Thank you SO much. I worked at this all days yesterday until 3am, and all I got working was the base and derived classes.

Programming gives a real sense of achievement when it works. I just wish I could find more examples on the internet to get a better sense of how code is meant to be put together. All I can find are VERY simple base classes and examples of when code is going wrong :-)

My chocolates (FoodProduct) can also be added and sold. And they expire correctly... and when they are expired I can throw away stock.

:-)