2017-09-20 7 views
-1

J'essaye d'écrire un programme qui permettra à l'utilisateur d'ajouter des articles dans un panier et de les supprimer. L'affectation consiste à utiliser la classe Bag qui est déjà fournie par l'instructeur. La classe ShoppingCart dérivera de la classe Bag. Je me bats avec l'héritage et je le compile.Classe Héritage & Modèle Classe C++

Je suis confondu avec le #include "Bag.cpp" à la fin du fichier Bag.h (qui est inclus par le professeur). Lorsque j'ajoute #include "ShoppingCart.cpp" et autres, cela me donne des erreurs différentes. Mais dans ce cas, j'obtiens l'erreur suivante. Si j'ajoute ces includes, j'obtiens des erreurs de redéfinition.

Je suis également confus avec les fichiers à inclure pour le processus de compilation sur PuTTy.

Je sais que c'est une très longue question, mais je serai heureux si quelqu'un a des réponses pour moi. Dans le main.cpp je n'ai pas essayé d'invoquer toutes les fonctions, fondamentalement je n'en ai pas fini avec le principal. Je vous remercie.

P.S. L'affectation nécessite que mes fichiers soient séparés en tant que fichiers d'en-tête/d'implémentation.

g++ -o main main.cpp Item.cpp 
Undefined      first referenced 
symbol        in file 
_ZN12ShoppingCartI4ItemEC1Ev  /var/tmp//cc52nA1n.o 
_ZN12ShoppingCartI4ItemE3addES0_ /var/tmp//cc52nA1n.o 
_Zeq4ItemS_       /var/tmp//cc52nA1n.o 
_ZN12ShoppingCartI4ItemE13getTotalPriceEv /var/tmp//cc52nA1n.o 
ld: fatal: symbol referencing errors. No output written to main 

BagInterface.h

#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 

Bag.h

#ifndef _BAG 
#define _BAG 

#include "BagInterface.h" 

template<class ItemType> 
class Bag : public BagInterface<ItemType> 
{ 
private: 
    static const int DEFAULT_BAG_SIZE = 10; 
    ItemType items[DEFAULT_BAG_SIZE]; // array of bag items 
    int itemCount;     // current count of bag items 
    int maxItems;      // max capacity of the bag 

    // Returns either the index of the element in the array items that 
    // contains the given target or -1, if the array does not contain 
    // the target. 
    int getIndexOf(const ItemType& target) const; 

public: 
    Bag(); 
    int getCurrentSize() const; 
    bool isEmpty() const; 
    bool add(const ItemType& newEntry); 
    bool remove(const ItemType& anEntry); 
    void clear(); 
    bool contains(const ItemType& anEntry) const; 
    int getFrequencyOf(const ItemType& anEntry) const; 
    vector<ItemType> toVector() const; 
}; // end Bag 

#include "Bag.cpp" 

#endif 

Bag.cpp

#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 

ShoppingCart.h

#ifndef SHOPPINGCART_H 
#define SHOPPINGCART_H 

#include "Bag.h" 
#include "Item.h" 

#include <iostream> 
#include <iomanip> 

using namespace std; 

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

}; 


#endif //SHOPPINGCART_H 

ShoppingCart.cpp

#include "ShoppingCart.h" 

using namespace std; 

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

template <class ItemType> 
bool ShoppingCart<ItemType>::add(Item newItem) { 

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

    totalPrice = totalPrice + (newItem.getQuantity() * newItem.getPrice()); 

    return added; 
} 

template <class ItemType> 
bool ShoppingCart<ItemType>::remove(Item anItem) { 

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

    totalPrice = totalPrice - (anItem.getQuantity() * anItem.getPrice()); 

    return removed; 
} 

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

Item.h

#ifndef ITEM_H 
#define ITEM_H 

#include <iostream> 
#include <iomanip> 
#include <string> 

using namespace std; 

class Item { 
private: 
    string name; 
    double price; 
    int quantity; 
public: 
    Item(); 
    Item(string n, double p, int q); 
    // Setters 
    void setName(string s); 
    void setPrice(double p); 
    void setQuantity(int q); 
    // Getters 
    string getName(); 
    double getPrice(); 
    int getQuantity(); 

    friend istream& operator >>(istream&, Item&); 

}; 

bool operator ==(Item i1, Item i2); 

Item operator <<(ostream& os, Item& source); 

#endif //ITEM_H 

Item.cpp

#include "Item.h" 
#include <string> 

using namespace std; 

Item::Item() { 

} 

Item::Item(string n, double p, int q) { 
    name = n; 
    price = p; 
    quantity = q; 
} 

// Setters 
void Item::setName(string n) { 
    name = n; 
} 
void Item::setPrice(double p) { 
    price = p; 
} 
void Item::setQuantity(int q) { 
    quantity = q; 
} 

// Getters 
string Item::getName() { 
    return name; 
} 
double Item::getPrice() { 
    return price; 
} 
int Item::getQuantity() { 
    return quantity; 
} 

// Definition of the friend function 
istream& operator >>(istream& ins, Item& target) 
{ 
    ins >> target.name >> target.price >> target.quantity; 

    return ins; 
} 

// Definition of non-member functions 
// << & == operator overloading 
bool operator ==(Item& i1, Item& i2) { 
    return (i1.getName()==i2.getName() && i1.getPrice()==i2.getPrice() 
      && i1.getQuantity()==i2.getQuantity()); 

} 

Item operator <<(ostream& os, Item& source) { 
    os << source.getName() << " " << source.getPrice() << " " <<source.getQuantity() << endl; 
} 

main.cpp

#include "ShoppingCart.h" 
#include "Item.h" 

#include <iostream> 
#include <iomanip> 
#include <string> 

using namespace std; 


int main() 
{ 
    cout << "Welcome to XXX SHOPPING CENTER" << endl; 

    Item items[10]; 
    ShoppingCart<Item> cart; 

    cout << "Enter the item you selected as the following order:\nname unitPrice quantity" 
     << "\n(Name can not contain any space. Otherwise errors happen!)" << endl; 

    cin >> items[0]; 

    cart.add(items[0]); 

    cout << "The shopping cart contains: " << endl; 

    cout << items[0]; 

    cout << "The total price of the order is " << cart.getTotalPrice() << endl; 



    return 0; 
} 
+3

double possible de [Pourquoi les modèles ne seront mis en œuvre dans le fichier d'en-tête?] (https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) –

+0

Dans cette rubrique, il est suggéré d'utiliser #include le fichier d'implémentation t la fin du fichier d'en-tête. Cependant, quand je fais cela, je reçois des erreurs de redéfinition pour chaque fonction qui existe dans le programme. – ongelo

+0

Les chances sont parce que votre IDE voit compiler et lie le fichier cpp. Changez le nom en quelque chose qui n'est pas cpp comme impl pour que les gens (et l'IDE) ne supposent pas qu'il doit être compilé.Une autre astuce consiste à ne pas séparer les implémentations des définitions de classe que vous ne gagnez pas beaucoup de la séparation dans le cas d'un en-tête. – user4581301

Répondre

0

Je pense que votre problème est dans l'opérateur == qui est utilisé par exemple getFrequencyOf() qui essaie de comparer l'élément const & et échoue car il n'y a pas approprié == défini n'importe où.

Il y a en fait plusieurs problèmes avec elle, et sans frontière claire entre votre code et le code d'affectation, il est difficile d'être sûr, mais ma meilleure estimation, que vous devriez changer

bool operator ==(Item i1, Item i2); 

à

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

puis, la mise en œuvre

// Definition of non-member functions 
// << & == operator overloading 
bool operator ==(Item& i1, Item& i2) { 
    return (i1.getName()==i2.getName() && i1.getPrice()==i2.getPrice() 
      && i1.getQuantity()==i2.getQuantity()); 

} 

à la version constCe qui, à son tour, ne compilerait pas puisque vous utilisez des getters non-const, donc tous ceux-ci devraient être const. Changez

// Getters 
string getName(); 
double getPrice(); 
int getQuantity(); 

à

// Getters 
const string& getName() const; 
//string getName(); 
double getPrice() const; 
int getQuantity() const; 

et

// Getters 
string Item::getName() { 
    return name; 
} 
double Item::getPrice() { 
    return price; 
} 
int Item::getQuantity() { 
    return quantity; 
} 

à

// Getters 
const string& Item::getName() const { 
    return name; 
} 
double Item::getPrice() const { 
    return price; 
} 
int Item::getQuantity() const { 
    return quantity; 
} 

après quoi vous devriez être en mesure de compiler et exécuter en incluant Bag.cpp comme vous professeur a fait à la fin de Bag.h et Shop pingCart.cpp à la fin de ShoppingCart.h

Je ne connais pas un bon moyen de partager plusieurs projets de fichiers, mais je suis sûr que l'inclusion des implémentations de modèles (Bag.cpp et ShoppingCart.cpp) ne le changera pas . Vos fichiers ont été compilés séparément puisque main.cpp supposait qu'il pourrait y avoir == operator pour const Item & quelque part. Item.cpp n'a pas eu de problèmes par lui-même. Et l'éditeur de liens vous a dit qu'il ne pouvait pas trouver toutes les fonctions dont il avait besoin.

MISE À JOUR:

Le code initial n'a pas été exécuté avec succès, mais pas à cause des problèmes avec des modèles ou compilation. Vous avez eu < < incorrect, avec le même problème: mauvaise signature de l'opérateur. Donc, pas getTotalPrice a été le dumping du noyau, mais cout < < Articles [0] car il n'a pas retourné ostream &. Voici mise à jour de travail REPL avec les modifications suivantes:

//Item operator <<(ostream& os, Item& source); 
std::ostream &operator <<(ostream& os, Item& source); 

et

//Item operator <<(ostream& os, Item& source) { 
// os << source.getName() << " " << source.getPrice() << " " <<source.getQuantity() << endl; 
//} 
std::ostream &operator <<(ostream& os, Item& source) { 
    return os << source.getName() << " " << source.getPrice() << " " <<source.getQuantity() << endl; 
} 

il sort:

gcc version 4.6.3 
Welcome to XXX SHOPPING CENTER 
Enter the item you selected as the following order: 
name unitPrice quantity 
(Name can not contain any space. Otherwise errors happen!) 
ooo 2 3 
The shopping cart contains: 
ooo 2 3 
The total price of the order is 6 
+0

Cela fonctionne très bien lorsque je copie le code dans un fichier et le compile. Ensuite, j'ai réussi à compiler la version de fichier multiple en entrant "g ++ -o main main.cpp Item.cpp". Cependant quand il s'agit de la fonction getTotalPrice(), il donne cette erreur: "Segmentation fault (core dumped)". La fonction fonctionne parfaitement lorsque je le compile dans un seul fichier. Je ne comprends pas pourquoi. Merci beaucoup pour la réponse, bien aidé! – ongelo

+0

Votre problème était mauvais << opérateur, pas un seul ou plusieurs fichiers ou modèles. Voir ma réponse mise à jour. –

+0

Merci ça m'a beaucoup aidé! – ongelo

-1

Je suggère fortement d'implémenter toutes vos fonctions de template dans les fichiers d'en-tête après (pas à l'intérieur de) la définition de classe, puis #incluant tous les fichiers .h normalement (en d'autres termes, ne pas #include vos fichiers .cpp). EDIT: Relire la question. Désolé, mon professeur nous a toujours demandé de les implémenter dans le même fichier s'ils étaient des modèles.

+0

Merci pour la réponse. Oui, malheureusement, ils doivent être dans des fichiers séparés, mais je préférerais que la tâche soit faite. Donc, je vais essayer votre suggestion. Je vous remercie. – ongelo