类继承和模板类C++
我正在尝试编写一个程序,允许用户将项目添加到购物车中并将其删除。任务是使用教师已经提供的Bag类。 ShoppingCart类将从Bag类派生。我正在努力继承并编译它。类继承和模板类C++
我对Bag.h文件(由教授收录)末尾的#include "Bag.cpp"
感到困惑。当我添加#include "ShoppingCart.cpp"
等,它给了我不同的错误。但在这种情况下,我收到以下错误。如果我添加这些包含,我会得到重新定义错误。
我也对PuTTy上的编译过程包含哪些文件感到困惑。
我知道这是一个很长的问题,但如果有人对我有一些答案,我会很高兴。在main.cpp中我没有尝试调用所有的函数,基本上我没有完成main。谢谢。
P.S.该分配要求我的文件作为头文件/实现文件分开。
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;
}
我认为你的问题出现在==运算符中,用于说getFrequencyOf(),它试图比较常量项&并失败,因为在任何地方都没有定义合适的==。
实际上有几个问题吧,没有你的代码和分配代码之间边界清晰,这是很难确定的,但我最好的猜测,你应该改变
bool operator ==(Item i1, Item i2);
到
bool operator ==(const Item& i1, const Item& i2);
然后,实施
// 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());
}
为const版本
// Definition of non-member functions
// << & == operator overloading
bool operator ==(const Item& i1, const Item& i2) {
return (i1.getName()==i2.getName() && i1.getPrice()==i2.getPrice()
&& i1.getQuantity()==i2.getQuantity());
}
因为你使用的是非const getters,所以所有这些都应该是const。变化
// Getters
string getName();
double getPrice();
int getQuantity();
到
// Getters
const string& getName() const;
//string getName();
double getPrice() const;
int getQuantity() const;
和
// 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;
}
之后,你应该能够编译并运行它由包括Bag.cpp你教授在Bag.h和Shop的最后做了在ShoppingCart.h结尾pingCart.cpp
我不知道分享多个文件项目的好方法,但我很确定包括模板实现(Bag.cpp和ShoppingCart.cpp)不会改变它。由于main.cpp假设某个地方可能存在==运算符,因此您的文件可能会分别编译为项目&。 Item.cpp本身没有问题。链接器告诉你,它无法找到它需要的所有功能。
UPDATE:
最初的代码没有成功运行,但不是因为使用模板或编译的问题。你有< <错误,与相同的问题:错误的操作员签名。所以不getTotalPrice是倾销的核心,但因为它没有返回ostream & cout < <项目[0]。下面是更新的工作REPL有以下变化:
//Item operator <<(ostream& os, Item& source);
std::ostream &operator <<(ostream& os, Item& source);
和
//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;
}
它输出:
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
我强烈建议在类定义之后(不在类内)实现头文件中的所有模板函数,然后根据需要正常包含所有.h文件(换句话说,不要#include你的.cpp文件)。编辑:重新阅读问题。对不起,我的老师总是让我们在同一个文件中实现他们,如果他们是模板。
谢谢你的回答。是的,不幸的是,他们必须在单独的文件中,但我宁愿完成任务。所以我会尝试你的建议。谢谢。 – ongelo
的可能的复制[为什么模板仅在头文件来实现?] (https://*.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) –
在这个主题中,建议使用#include执行文件a t头文件的结尾。但是,当我这样做时,那么我对程序中存在的每个函数都会产生重定义错误。 – ongelo
这是因为您的IDE看到编译并链接cpp文件。将名称更改为不像cpl那样的cpp,以便人们(和IDE)不会假定它将被编译。另一个诀窍是不要将实现从类头定义中分离出来,而在头文件的情况下,这些类定义并没有从分离中获益。 – user4581301