在附加的代码中,对于我的类文件中的每个函数,我都无法超越错误function template has already been defined
。
我已经全力以赴,无法弄清楚功能已在任何地方定义。请注意,这段代码是在阅读一本书的章节时编写的,只是尝试创建功能代码以便开始。
BagInterface.h:
/** @file BagInterface.h */
#ifndef BAG_INTERFACE_
#define BAG_INTERFACE_
#include <vector>
using std::vector;
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;
/** See 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 addedd 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 the items is 0. */
virtual void clear() = 0;
/** Counts the number of times a given entry appears in this 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 top 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 copies of all the entries in this bag. */
virtual vector<ItemType> toVector() const = 0;
/** Destroys this bag and frees its assigned memory. */
virtual ~BagInterface() { }
}; // end BagInterface
#endif
ArrayBag.h:
/** @file ArrayBag.h */
#ifndef ARRAY_BAG_
#define ARRAY_BAG_
#include "BagInterface.h"
template<class ItemType>
class ArrayBag : public BagInterface<ItemType>
{
private:
static const int DEFAULT_CAPACITY = 6;
ItemType items[DEFAULT_CAPACITY];
int itemCount;
int maxItems;
int getIndexOf(const ItemType& target, int searchIndex) const;
int countFrequency(const ItemType& target, int searchIndex) const;
public:
ArrayBag();
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;
};
#include "ArrayBag.cpp"
#endif
ArrayBag.cpp:
#include "ArrayBag.h"
template<class ItemType>
ArrayBag<ItemType>::ArrayBag() : itemCount(0), maxItems(DEFAULT_CAPACITY)
{
}
template<class ItemType>
int ArrayBag<ItemType>::getIndexOf(const ItemType& target, int searchIndex) const
{
int result = -1;
if (searchIndex < itemCount)
{
if (items[searchIndex] == target)
{
result = searchIndex;
}
else
{
result = getIndexOf(target, searchIndex + 1);
}
}
return result;
}
template<class ItemType>
bool ArrayBag<ItemType>::add(const ItemType& newEntry)
{
bool hasRoomToAdd = (itemCount < maxItems);
if (hasRoomToAdd)
{
items[itemCount] = newEntry;
itemCount++;
}
return hasRoomToAdd;
}
template<class ItemType>
vector<ItemType> ArrayBag<ItemType>::toVector() const
{
vector<ItemType> bagContents;
for (int i = 0; i < itemCount; i++)
bagContents.push_back(items[i]);
return bagContents;
}
template<class ItemType>
int ArrayBag<ItemType>::getCurrentSize() const
{
return itemCount;
}
template<class ItemType>
bool ArrayBag<ItemType>::isEmpty() const
{
return itemCount == 0;
}
template<class ItemType>
bool ArrayBag<ItemType>::remove(const ItemType& anEntry)
{
int locatedIndex = getIndexOf(anEntry, 0);
bool canRemoveItem = !isEmpty() && (locatedIndex > 1);
if (canRemoveItem)
{
itemCount--;
items[locatedIndex] = items[itemCount];
}
return canRemoveItem;
}
template<class ItemType>
void ArrayBag<ItemType>::clear()
{
itemCount = 0;
}
template<class ItemType>
int ArrayBag<ItemType>::getFrequencyOf(const ItemType& anEntry) const
{
return countFrequency(anEntry, 0);
}
template<class ItemType>
int ArrayBag<ItemType>::countFrequency(const ItemType& target, int searchIndex) const
{
int frequency = 0;
if (searchIndex < itemCount)
{
if (items[searchIndex] == target)
{
frequency = 1 + countFrequency(target, searchIndex + 1);
}
else
{
frequency = countFrequency(target, searchIndex + 1);
}
}
return frequency;
}
template<class ItemType>
bool ArrayBag<ItemType>::contains(const ItemType& anEntry) const
{
bool found = false;
int curIndex = 0;
while (!found && (curIndex < itemCount))
{
if (anEntry == items[curIndex])
found = true;
else
curIndex++;
}
return found;
}
Bag.cpp:
#include <iostream>
#include <string>
#include "ArrayBag.h"
using std::cout;
using std::endl;
void displayBag(ArrayBag<std::string>& bag)
{
cout << "The bag contains " << bag.getCurrentSize() << " items:" << endl;
vector<std::string> bagItems = bag.toVector();
int numberOfEntries = (int)bagItems.size();
for (int i = 0; i < numberOfEntries; i++)
{
cout << bagItems[i] << " ";
}
cout << endl << endl;
}
void bagTester(ArrayBag<std::string>& bag)
{
cout << "isEmpty: returns " << bag.isEmpty() << "; should be 1 (true)" << endl;
displayBag(bag);
std::string items[] = { "one","two", "three", "four", "five", "one" };
cout << "Add 6 items to the bag: " << endl;
for (int i = 0; i < 6; i++)
{
bag.add(items[i]);
}
displayBag(bag);
cout << "isEmpty: returns " << bag.isEmpty() << "; should be 0 (false)" << endl;
cout << "getCurrentSize: returns " << bag.getCurrentSize() << "; should be 6" << endl;
cout << "Try to add another entry: add(\"extra\") returns " << bag.add("extra") << endl;
}
int main()
{
ArrayBag<std::string> bag;
cout << "Testing the Array-Based Bag:" << endl;
cout << "The initial bag is empty." << endl;
bagTester(bag);
cout << "All done!" << endl;
std::cin.get();
return 0;
}
答案 0 :(得分:-1)
我已经复制了你的问题,并了解发生了什么。具有include ArrayBag.cpp
的不寻常构造工作正常,只要您不编译它,并且只是将其用作“标题”。但它的内容必须在每个翻译单元中只出现一次。这就是为什么我们要包含警卫:你#include
应该包含警卫的任何文件,以及ArrayBag.cpp
dos。这是怎么回事:
编译Arraybag.cpp,
包含ArrayBag.h中的声明,但
然后ArrayBag.h包含Arraybag.cpp,它没有自己的包含保护
解析 definitions ,并在Arraybag.cpp结束后,解析继续在ArrayBag.h的末尾。
我们现在完成了ArrayBag.cpp编译的第一行,但我们仍在解析它:我们再次遍历ArrayBag.cpp 的其余部分。
为了它,您仍然可以编译ArrayBag.cpp
:
ArrayBag.cpp
// would just be
#include "ArrayBagDefinitions.h"
并且ArrayBagDefinitions.h
将是您的旧ArrayBag.cpp文件,但包含防护。然后你的代码可以用vs2017编译好。
答案 1 :(得分:-1)
你能否展示一下makefile,环境,编译器?我编译了whitout问题,我在windows下使用qt creator IDE(mingw32),并且makefile是由qmake自动创建的,所以,我支持你的问题可能在makefile中,我知道这是一个评论,但由于我的声誉,我无法发表评论,因此,在您显示makefile后,我会帮助您。
请避免标记为否定此答案,我正在尝试帮助,并提高我的声誉。如果答案不具有破坏性,请告诉我,我会删除它。
代码的输出是:
答案 2 :(得分:-2)
在你的书中,他们是否提到不编译ArrayBag.cpp
?
在C ++中,编译器在模板类实例化时生成代码。我们可靠的朋友没有定义就无法做到这一点。因此,定义需要在编译时可用( there's more reasons why )。为了便于阅读,您经常会看到人们将declaration
模板类与definition
分开。
正如本书向您展示的那样,我们可以利用#include
向编译器提供定义,同时将两者分开。
这里需要注意的是,您无法编译用于分隔定义的文件。根据在ArrayBag.cpp
被包含在其他地方之前是否编译ArrayBag.h
,当编译器发现您已经尝试定义ArrayBag
时,编译器会有一种适应性。
或者,您可以在ArrayBag.cpp
中添加包含保护,这将阻止编译器在编译ArrayBag
期间再次尝试定义ArrayBag.cpp
,但我不建议这样做。它会在编译期间增加不必要的时间。毕竟,我们在这里滥用#include
的简单性来缓解编译器要求中的痛点。
如果您正在使用Visual Studio,则可以通过右键单击解决方案资源管理器中的文件&gt; 属性将.cpp
文件视为头文件&gt; 一般&gt; 从构建中排除:是