Hi guys,

Well, I am currently taking a C++ course focusing on learning about object-oriented design concepts, including polymorphism. The assignment I am currently working on involves the creation of a point-of-sale system. The details of the problem are quite involved and challenging (for me, at least!). I am determined to solve the problem myself, however, I am in real need of some help.

We have been provided with /some/ code for the project. This has been helpful but also creates certain constraints for the way in which the project is completed. The partial solution we have been provided with used arrays for storing product codes. I wish to instead use a map which contains a string with the product code of various items as the key, paired to a pointer to each product.

I should add, at this point, that there are three different types of product:

1 - Standard product line (product code, no serial number, no expiry date)
2 - Itemized product line (product code, serial number, no expiry date)
3 - Perishable product line (product code, no serial number, expiry date)

However, my current issue is with the implementation of a map. I am currently working with more than five classes, so the following is supposed to be a helpful excerpt. May I say beforehand how grateful I am to those of you who are taking the time to read the code. Here is some code to demonstrate where I am up to:

class Inventory{
    public:
        static void AddProduct(ProductLine* prod);
        static void SellProduct(ProductCode const& prod, int qty);
        static void IncreaseStock(ProductCode const& prod, int qty);
        static ProductLine* GetProduct(ProductCode const& prod);

    private:
        static map<string, ProductLine*, less<string> > productMap;
        static int numberProds;
};
using namespace std;

int Inventory::numberProds = 0;

// add another product line
void Inventory::AddProduct(ProductLine* prod)
{
    // add product then increment the total number of products
    productMap.insert (prod->GetCode(), prod);
    numberProds++;
}

It is quite difficult to present a single portion of this problem clearly, as there are so many different things involved in making it work. However, being able to make the map work would be very helpful. I have not included the other functions as I wish to work them out for myself.

I would be happy to post more of the code I have, but I do not want to give the impression that I do not want to solve the problem, myself. If I have not been clear, I apologize - after you have been looking at a problem for a while, you can make the mistake of assuming that you have explained everything when you haven't.

Thank you to all of you who have taken the time to read this post.

Kind regards,

Daniel

NB: The class declaration of Inventory was provided except for the map component. It is this component that I am trying to make work. I just wanted to make sure that I am not unintentionally passing off someone else's work as my own. D

Recommended Answers

All 10 Replies

static map<string, ProductLine*, less<string> > productMap;

Have a look at this page. I think you're trying to combine 2 of the 3 versions of the std::map constructor into 1 unrecognized version.

I suggest you try it without the less<string> and see if it works properly. This should call the first version of the constructor as listed on the linked page. You may need to figure out how to switch to the second version on the linked page though (which I think you were trying to use).

Hey Fbody,

Thanks for joining the fray! I tried your suggestion of removing the comparison component (less <string>). Unfortunately, I didn't make any headway. Something I should have included is the error message produced by the compiler:

Inventory.cpp: In static member function 'static void Inventory::AddProduct(ProductLine*)':
Inventory.cpp:16: error: no matching function for call to 'std::map<std::string, ProductLine*, std::less<std::string>, std::allocator<std::pair<const std::string, ProductLine*> > >::insert(ProductCode, ProductLine*&)'
/usr/include/c++/4.0.0/bits/stl_map.h:359: note: candidates are: std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, _Alloc>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::insert(const std::pair<const _Key, _Tp>&) [with _Key = std::string, _Tp = ProductLine*, _Compare = std::less<std::string>, _Alloc = std::allocator<std::pair<const std::string, ProductLine*> >]
/usr/include/c++/4.0.0/bits/stl_map.h:383: note: typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, _Alloc>::iterator std::map<_Key, _Tp, _Compare, _Alloc>::insert(typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, _Alloc>::iterator, const std::pair<const _Key, _Tp>&) [with _Key = std::string, _Tp = ProductLine*, _Compare = std::less<std::string>, _Alloc = std::allocator<std::pair<const std::string, ProductLine*> >]
make[2]: *** [build/Debug/GNU-MacOSX/Inventory.o] Error 1
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2
BUILD FAILED (exit value 2, total time: 1s)

Thanks again for taking a look at the problem.

Cheers,

Daniel

PS: I am using the NetBeans IDE on a MacBook Pro, running Leopard.

Can you post the error that you're getting when you compile without the less<string> parameter?

I think it would also be beneficial if you posted some information about ProductLine and the related derivations.

Hi Fbody,

Here is the error code I receive when I use:

map<string, ProductLine*, less<string> > productMap;

This is interesting because it seems to be producing the same message. Maybe I am not including the map class properly, or maybe an inheritance issue.

Inventory.cpp: In static member function 'static void Inventory::AddProduct(ProductLine*)':
Inventory.cpp:16: error: no matching function for call to 'std::map<std::string, ProductLine*, std::less<std::string>, std::allocator<std::pair<const std::string, ProductLine*> > >::insert(ProductCode, ProductLine*&)'
/usr/include/c++/4.0.0/bits/stl_map.h:359: note: candidates are: std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, _Alloc>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::insert(const std::pair<const _Key, _Tp>&) [with _Key = std::string, _Tp = ProductLine*, _Compare = std::less<std::string>, _Alloc = std::allocator<std::pair<const std::string, ProductLine*> >]
/usr/include/c++/4.0.0/bits/stl_map.h:383: note: typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, _Alloc>::iterator std::map<_Key, _Tp, _Compare, _Alloc>::insert(typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, _Alloc>::iterator, const std::pair<const _Key, _Tp>&) [with _Key = std::string, _Tp = ProductLine*, _Compare = std::less<std::string>, _Alloc = std::allocator<std::pair<const std::string, ProductLine*> >]
make[2]: *** [build/Debug/GNU-MacOSX/Inventory.o] Error 1
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2
BUILD FAILED (exit value 2, total time: 839ms)

Here is some more code:

ProductLine and ProductCode Header File

using namespace std;

class ProductCode{

    friend ostream& operator<<(ostream& out, const ProductCode& pc);

    public:

    ProductCode(char code[]);

    bool operator==(const ProductCode& other);

    private:

    char productCode[6];

};

class ProductLine{

    public:

    ProductLine(ProductCode pc, double rrp, double sp, int oh, char* desc);

    ~ProductLine();

    virtual void Sold(int qty);

    ProductCode GetCode();

    protected:

    ProductCode productCode;

    double recRetPrice;

    double salePrice;

    int onHand;

    int soldToday;

    char* description;

};

Definition

// Since ProductCode is only used with class ProductLine
// (and its descendants), include declaration and
// implementation in same files as for ProductLine

// ProductCode constructor. Copies code to productCode. Note: check string length not equal to five

ProductCode::ProductCode(char* code)
{
    // if(strlen(code) != 5) - fix this later
    strcpy(productCode, code);
}

// compare two product codes to determine if they are the same. Returns true if items are the same

bool ProductCode::operator==(const ProductCode& other)
{
    bool equal = false;

    if(strcmp(productCode, other.productCode) == 0)
        equal = true;
    return equal;
}

// overload << operator. Accept an ostream object and a reference to a ProductCode object. Read product code into the ostream and then return it.

ostream& operator<<(ostream& out, const ProductCode& pc)
{
      out << pc.productCode;
      return out;
}

// ProductLine constructor accepts, a product code, retail price, sale price, on hand quantity and a description.
// Assigns values to various variables.

ProductLine::ProductLine(ProductCode pc, double rrp, double sp, int oh, char* desc):

    productCode(pc), recRetPrice(rrp), salePrice(sp), onHand(oh),

    soldToday(0)
{
    // create array of length desc + 1 (for null character)
    description = new char[strlen(desc) + 1];

    // copy contents of desc to description
    strcpy(description, desc);
}

// default destructor

ProductLine::~ProductLine()
{
    // delete array description

    delete [] description;
}

// function used to record the sale of a product

void ProductLine::Sold(int qty)
{

    // if the requested quantity is greater than available - no sale.
    if(qty > onHand)
    {
        cout << "Only " << onHand << " available - Sale cancelled" << endl;
    }
    // otherwise all good. Reduce onHand by one and increase the number sold today by one.
    else
    {
        cout << "Total Price: " << qty * salePrice << endl;

        onHand -= qty;

        soldToday += qty;
    }

}

ProductCode ProductLine::GetCode()
{

    // returns the product code associated with

    return productCode;
};

I think I indicated that I am, in fact, trying to change the structures used to implement the system, from arrays to a map. In another class (an itemized product line), I have made use of a set to store serial numbers. Once again, the code I have included is structurally built from that of my instructor. I have gone through and commented the code in order to better understand it, myself. It will be clear from what I have included that I have a fair bit of work to do to re-engineer the whole thing. Thanks again, Fbody, for your time.

Daniel

I think you're confused about how the insert member function works for the vector class. You'd probably be better off simply using the overloaded subscript operator:

productMap[prod->GetCode()] = prod;
static map<string, ProductLine*, less<string> > productMap;

less<KeyType> is already the default predicate, you don't need to specify it unless you want a different ordering. Also note that your key type is string while prod->GetCode() returns a ProductCode object with no implicit conversion to string. I suspect you really want the key type to be ProductCode.

Ok, guys, I think I am starting to get there. Firstly, I realized that I had not provided the implementation for the comparison operator, which my instructor did point out we had to do. You are absolutely right, Narue, when you suggest that the key should be of type ProductCode. Here is what I have now:

using namespace std;

class Inventory{

    public:

       static void AddProduct(ProductLine* prod);

        static void SellProduct(ProductCode const& prod, int qty);

        static void IncreaseStock(ProductCode const& prod, int qty);

        static ProductLine* GetProduct(ProductCode const& prod);

        ProductCode operator<(const ProductCode& other)const{
           return productCode < other.productCode;}


    private:

        static map<ProductCode, ProductLine*, less<ProductCode> > productMap;

        static int numberProds;

};
void Inventory::AddProduct(ProductLine* prod)
{
    // add product then increment the total number of products

    productMap.insert (pair<ProductCode,ProductLine*>(prod->GetCode(), prod));

    numberProds++;
}

Here is the new (improved, I hope!) error message:

Inventory.h: In member function 'ProductCode Inventory::operator<(const ProductCode&) const':
Inventory.h:29: error: 'productCode' was not declared in this scope
ProductLine.h:27: error: 'char ProductCode::productCode [6]' is private
Inventory.h:29: error: within this context
make[2]: *** [build/Debug/GNU-MacOSX/Application.o] Error 1
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2
BUILD FAILED (exit value 2, total time: 764ms)

It seems to need an instance of the ProductCode to "exist" when the class is declared. Any ideas, guys? Thanks in advance.

Daniel

The overloaded operator< is mostly correct. However, it should return a bool and probably should be a member of ProductCode, not Inventory.

With it being a member of Inventory, it does not have access to the members of the ProductCode class.
This is why you are getting

...
Inventory.h:29: error: 'productCode' was not declared in this scope
ProductLine.h:27: error: 'char ProductCode::productCode [6]' is private
...

.

So here is the new error message, after:

1 - Moving overloaded operator to ProductCode.
2 - Changing return type to bool.

ndefined symbols:
"Inventory::productMap", referenced from:
__ZN9Inventory10productMapE$non_lazy_ptr in Inventory.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make[2]: *** [dist/Debug/GNU-MacOSX/posaic] Error 1
make[1]: *** [.build-conf] Error 2
make: *** [.build-impl] Error 2
BUILD FAILED (exit value 2, total time: 1s)

I feel like we are really close here, guys!

Daniel

productMap is static, which is good. This causes there to be only 1 instance of the map that is shared by all instances of Inventory. As such, it needs to be treated like a variable that is globally scoped, but only accessible by members of Inventory. Have you created any sort of initialization/declaration statement outside the class definition, in the global scope?

Read this page for more info. The section you want is toward the bottom. I'm not real sure how you would apply this to a map though...

Seems like something like this would work (don't know what your current declaration looks like, just guessing):

map<ProductCode, ProductLine*> Inventory::productMap;

That's it, guys! Here is what eventually worked:

using namespace std;

class Inventory{

    public:

       static void AddProduct(ProductLine* prod);

        static void SellProduct(ProductCode const& prod, int qty);

        static void IncreaseStock(ProductCode const& prod, int qty);

        static ProductLine* GetProduct(ProductCode const& prod);

        


    private:

        static map<ProductCode, ProductLine*, less<ProductCode> > productMap;

        static int numberProds;

};
#include "ProductLine.h"
#include "Inventory.h"
#include <iostream>
#include <map>

using namespace std;

int Inventory::numberProds = 0;

map<ProductCode, ProductLine*, less<ProductCode> > Inventory::productMap;

// add another product line

void Inventory::AddProduct(ProductLine* prod)
{
    // add product then increment the total number of products

    productMap.insert (pair<ProductCode,ProductLine*>(prod->GetCode(), prod));

    numberProds++;
}

You guys were absolutely fantastic! Thank you so much for your time and effort. I have to say that this assignment has really seen me working outside my comfort level in terms of my knowledge, so having the ability to turn to you guys was amazing. Again, my heartiest thanks.

Kind regards,

Daniel

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.