0

I am working on a project for a class. The project is about inheritance. My professor provided us with a base class and gave us instructions to override some of the functions in the base class in the derived class we were asked to create. All of my objects and the client compile separately, but when I try to put it all together I encounter a problem. header, implementation, and client must be separate in this project.

g++ product.o basket.o client.o
client.o:client.cpp:(.text+0x37): undefined reference to`Cart<item>::Cart()'
client.o:client.cpp:(.text+0x147): undefined reference to `Cart<item>::add(item)'
client.o:client.cpp:(.text+0x27b): undefined reference to `Cart<item>::getTotalPrice()'
client.o:client.cpp:(.text+0x3d7): undefined reference to `Cart<item>::add(item)'
client.o:client.cpp:(.text+0x4df): undefined reference to `Cart<item>::remove(item)'
client.o:client.cpp:(.text+0x5fd): undefined reference to `Cart<item>::getTotalPrice()'
client.o:client.cpp:(.text$_ZNK3BagI4itemE10getIndexOfERKS0_[__ZNK3BagI4itemE10getIndexOfERKS0_]+0x4f): undefined reference to `operator==(item const&, item const&)'
client.o:client.cpp:(.text$_ZNK3BagI4itemE14getFrequencyOfERKS0_[__ZNK3BagI4itemE14getFrequencyOfERKS0_]+0x45): undefined reference to `operator==(item const&, item const&)'
collect2.exe: error: ld returned 1 exit status

Here is the code for base class:

#ifndef _BAG_INTERFACE
#define _BAG_INTERFACE

#include <vector>
using namespace std;

template<class ItemType>
class BagInterface
{
    public:
       /** Gets the current number of entries in this bag.
        @return The integer number of entries currently in the bag. */
       virtual int getCurrentSize() const = 0;

       /** Sees whether this bag is empty.
        @return True if the bag is empty, or false if not. */
       virtual bool isEmpty() const = 0;

       /** Adds a new entry to this bag.
        @post  If successful, newEntry is stored in the bag and
           the count of items in the bag has increased by 1.
        @param newEntry  The object to be added as a new entry.
        @return  True if addition was successful, or false if not. */
       virtual bool add(const ItemType& newEntry) = 0;

       /** Removes one occurrence of a given entry from this bag,
           if possible.
        @post  If successful, anEntry has been removed from the bag
           and the count of items in the bag has decreased by 1.
        @param anEntry  The entry to be removed.
        @return  True if removal was successful, or false if not. */
       virtual bool remove(const ItemType& anEntry) = 0;

       /** Removes all entries from this bag.
        @post  Bag contains no items, and the count of items is 0. */
       virtual void clear() = 0;

       /** Counts the number of times a given entry appears in bag.
        @param anEntry  The entry to be counted.
        @return  The number of times anEntry appears in the bag. */
       virtual int getFrequencyOf(const ItemType& anEntry) const = 0;

       /** Tests whether this bag contains a given entry.
        @param anEntry  The entry to locate.
        @return  True if bag contains anEntry, or false otherwise. */
       virtual bool contains(const ItemType& anEntry) const = 0;

       /** Empties and then fills a given vector with all entries that
           are in this bag.
        @return  A vector containing all the entries in the bag. */
       virtual vector<ItemType> toVector() const = 0;
    }; // end BagInterface
#endif


#include "Bag.h"
#include <cstddef>
template<class ItemType>
Bag<ItemType>::Bag() : itemCount(0), maxItems(DEFAULT_BAG_SIZE)
{
}  // end default constructor

template<class ItemType>
int Bag<ItemType>::getCurrentSize() const
{
    return itemCount;
}  // end getCurrentSize

template<class ItemType>
bool Bag<ItemType>::isEmpty() const
{
    return itemCount == 0;
}  // end isEmpty

template<class ItemType>
bool Bag<ItemType>::add(const ItemType& newEntry)
{
    bool hasRoomToAdd = (itemCount < maxItems);
    if (hasRoomToAdd)
    {
        items[itemCount] = newEntry;
        itemCount++;
    }  // end if

    return hasRoomToAdd;
}  // end add

template<class ItemType>
bool Bag<ItemType>::remove(const ItemType& anEntry)
{
   int locatedIndex = getIndexOf(anEntry);
    bool canRemoveItem = !isEmpty() && (locatedIndex > -1);
    if (canRemoveItem)
    {
        itemCount--;
        items[locatedIndex] = items[itemCount];
    }  // end if

    return canRemoveItem;
}  // end remove

template<class ItemType>
void Bag<ItemType>::clear()
{
    itemCount = 0;
}  // end clear

template<class ItemType>
int Bag<ItemType>::getFrequencyOf(const ItemType& anEntry) const
{
   int frequency = 0;
   int searchIndex = 0;
   while (searchIndex < itemCount)
   {
      if (items[searchIndex] == anEntry)
      {
         frequency++;
      }  // end if

      searchIndex++;
   }  // end while

   return frequency;
}  // end getFrequencyOf

template<class ItemType>
bool Bag<ItemType>::contains(const ItemType& anEntry) const
{
    return getIndexOf(anEntry) > -1;
}  // end contains

/* ALTERNATE 1
template<class ItemType>
bool Bag<ItemType>::contains(const ItemType& anEntry) const
{
    return getFrequencyOf(anEntry) > 0;
}  // end contains
*/
/* ALTERNATE 2 
template<class ItemType>
bool Bag<ItemType>::contains(const ItemType& anEntry) const
{
   bool found = false;
   for (int i = 0; !found && (i < itemCount); i++)
   {
      if (anEntry == items[i])
      {
         found = true;
      } // end if
   } // end for

   return found;
}  // end contains
*/

template<class ItemType>
vector<ItemType> Bag<ItemType>::toVector() const
{
    vector<ItemType> bagContents;
    for (int i = 0; i < itemCount; i++)
        bagContents.push_back(items[i]);
   return bagContents;
}  // end toVector

// private
template<class ItemType>
int Bag<ItemType>::getIndexOf(const ItemType& target) const
{
    bool found = false;
   int result = -1;
   int searchIndex = 0;
   // if the bag is empty, itemCount is zero, so loop is skipped
   while (!found && (searchIndex < itemCount))
   {
      if (items[searchIndex] == target)
      {
         found = true;
         result = searchIndex;
      } 
      else
      {
         searchIndex++;
      }  // end if
   }  // end while

   return result;
}  // end getIndexOf

Here is the code for the derived class

#ifndef BASKET_H
#define BASKET_H

#include "Bag.h"
#include "product.h"

#include <iostream>
#include <iomanip>

using namespace std;

template <class ItemType>
class Cart : public Bag<ItemType> {
private:
    double totalPrice;
public:
    Cart();
    double getTotalPrice();
    bool add(item);
    bool remove(item);

};

#endif

#include "basket.h"

using namespace std;

// Default Constructor
template <class ItemType>
Cart<ItemType>::Cart() {
    totalPrice = 0;
}

template <class ItemType>
bool Cart<ItemType>::add(item newItem) {

    bool added = Bag<ItemType>::add(newItem);

    totalPrice = totalPrice + (newItem.getitemQuantity() * newItem.getitemPrice());

    return added;
}

template <class ItemType>
bool Cart<ItemType>::remove(item anItem) {

    bool removed = Bag<ItemType>::remove(anItem);

    totalPrice = totalPrice - (anItem.getitemQuantity() * anItem.getitemPrice());

    return removed;
}

template <class ItemType>
double Cart<ItemType>::getTotalPrice() {
    return totalPrice;
}

Here is my main program:

#pragma once
#include <string>
#include "item2.h"
#include "Cart2.h"
#include "Bag.h"
#include "BagInterface.h"


using namespace std;

int main()
{


    item itemIn;
    Cart<item> shoppingCart;
    Bag<item> itemInBag;
    int itemCount = 0;
    vector<item> showItems;
    int modification = 1;

    char modify = 'y';
    char proceed = 'y';

    cout << "hello, thanks for shopping with us" << endl;
    cout << "please entr your items as the following: ItemName UnitPrice Quantity" << endl;
    cout << "other input formats will casue error!" << endl << "--> " <<endl;

    while (proceed == 'y')
    {
        cin >> itemIn;
        shoppingCart.add(itemIn);

        cout << "do you wish to add another item? " << endl << "--> ";
        cin >> proceed;

        if (proceed = 'n')
        {break;}

    }

    itemCount = itemInBag.getCurrentSize();
    showItems = itemInBag.toVector();
    for (int i = 0; i < itemCount; ++i)
    {
        cout << showItems[i];
    }

    cout << "would you like to modify your order? y/n" << endl << "--> " << endl;
    cin >> modify;

    while (modify = 'y')
    {
        cout << "do you want to (1) add an item or (2) remove an item? Press the coresponding number." << endl << "-->" << endl;
        cin >> modification;

        if (modification = 1)
        {

        }

    }
    cout << "done";
    return 0;


}

Here is the other class we were asked to make:

#ifndef PRODUCT_H
#define PRODUCT_H
#include <iostream>
#include <cstdlib>
#include <string>
#include <iomanip>
using namespace std;

class item
{
    private:
        string itemName;
        double itemPrice;
        int itemQuantity;
    public:
        item();
        void setitemName(string);
        void setitemPrice(double);
        void setitemQuantity(int);
        string getitemName() const;
        double getitemPrice() const;
        int getitemQuantity() const;
        friend ostream& operator<<(ostream& os, const item& right);
        friend istream& operator>>(istream& is, item& right);

};

bool operator ==(const item& i1, const item& i2);

#endif  

#include "product.h"
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <string>
using namespace std;

item::item()
{

}

void item::setitemName(string x)
{
    itemName = x;
}

void item::setitemPrice(double y)
{
    itemPrice = y;

}

void item::setitemQuantity(int z)
{
    itemQuantity = z;
}

string item::getitemName() const
{
    return itemName;
}

double item::getitemPrice() const
{
    return itemPrice;
}

int item::getitemQuantity() const
{
    return itemQuantity;
}

ostream& operator<<(ostream& os, const item& right)
{
    os <<right.itemName << right.itemPrice << right.itemQuantity << endl;
    return os;
}

istream& operator>>(istream& is, item& right)
{
    is >> right.itemName >> right.itemPrice >> right.itemQuantity;
    return is;
}   

bool operator ==(item& i1, item& i2) 
{
    return (i1.getitemName()==i2.getitemName() && i1.getitemPrice()==i2.getitemPrice()
            && i1.getitemQuantity()==i2.getitemQuantity());

}

If I am reading the compiler right the problem is probably in the derived class. I am not sure what is going on and would appreciate any help that anyone can give.(Note: My main program isn't finished.)

Caschmitt
  • 3
  • 2
  • See the linked duplicate. The implementation of template class members must be included where they are instantiated; you can't implement them in a separate .cpp file. Either put them in the .hpp file or create a .tpp file and then #include that into the .hpp file. – cdhowie Sep 23 '17 at 01:54
  • Define "code for the derived class". Is everything you showed in one header file, `basket.h`, and if so why does it have a ifndef/define guard for only half of its contents, and then it includes itself? – Sam Varshavchik Sep 23 '17 at 01:54
  • no, they are in separate file in accordance with the requirements of the project. I am talking about cart.cpp and cart.h – Caschmitt Sep 23 '17 at 02:03

0 Answers0