创建 C++ 集合类






2.11/5 (9投票s)
2004年3月9日
4分钟阅读

120319
如何使用模板创建自定义集合类,并利用 C++ std::vector STL 库以及运算符。我期望您能够理解指针、类、模板和运算符的工作原理。
引言
C++ 提供了自己的 STL(标准模板库)容器(例如 std::vector
)。最好使用这些容器而不是自己编写,因为 C++ 设计者们在确保性能方面付出了巨大的努力。
为什么要使用集合类?
“集合类是一种容器类,用于存储一个或多个特定类型的项”
举例来说,我想开发一个游戏,其中有一个包含 9 个按钮的棋盘。每个按钮都有一个开或关的状态。每个按钮位于棋盘上的特定 x,y 位置,并且其颜色取决于其状态以及点击该按钮的玩家。下图显示了包含九个按钮的棋盘。
图 1。
在代码方面,我将有一个包含按钮集合的棋盘类。下图显示了棋盘类的 UML 表示。
图 2。
集合类将允许我们访问每个按钮及其属性和函数(例如状态、x 和 y 位置、颜色)。
好了,开始编码吧。
代码
集合类的代码相当简单。如果您理解指针、类、模板和运算符的工作原理,那么您已经完成了 90%。剩下的就是将这些技术结合起来,“ voilà!”您就会拥有自己的集合类。
在您喜欢的 C++ 编译器中,创建一个新的 win32 项目和一个头文件。我称我的为“TCollection.h”。
然后将以下代码行添加到头文件中
#include <vector> using namespace std; //This simply includes the vector container from the STL. //Next we create the template class: template <class TBase>class TCollection{ };
创建模板类后,我们首先添加受保护的 vector 成员。设置为受保护是因为我们希望派生自集合类的类能够访问该成员。
template <class TBase> class TCollection { protected: //The Vector container that will hold the collection of Items vector<TBase> m_items; };
基本上,我们需要对我们的容器执行三件事:添加项、删除项和清空容器。我们还想知道容器中有多少项,为此我们将需要一个 Count()
函数。所有这些函数都将是公共的。
Add()
函数
由于我们已经知道要将 TBase
类型的项添加到容器中,因此我们只需声明并定义一个 Add()
函数。
int Add(void) { //Create a new base item TBase BaseItem; //Add the item to the container m_items.push_back(BaseItem); //Return the position of the item within the container. //Zero Based return (m_items.size()-1); }
Remove()
函数
对于 Remove()
函数,我们需要声明并定义一个返回指向要删除项的指针的函数。这是因为我们的 vector 容器的 erase 函数需要一个指针才能删除一个项。
//Function to return the memory address of a specific Item TBase* GetAddress(int ItemKey) { return &(m_items[ItemKey]); }
始终最好进行防御性编程,但出于本文的考虑,我没有这样做,因为我想展示集合类背后的原理。例如,您可以在返回项的地址之前测试该项是否真的存在于容器中。
现在我们有了 GetAddress()
函数,我们可以继续我们的 remove 函数。
void Remove(int ItemKey) //Remove a specific Item from the collection { //Remove the Item using the vector’s erase function m_items.erase(GetAddress(ItemKey)); }
Clear()
函数
Clear
函数非常简单。
void Clear(void) //Clear the collection { m_items.clear(); }
Count()
函数
Count
函数也非常简单。
//Return the number of items in collection int Count(void) { return m_items.size(); //One Based }
请注意,返回的数字是基于一的。这意味着要访问集合中的最后一个项,您需要使用 Count()-1
。
现在我们已经有了所有的函数,我们只需要再做一件事。我们希望通过使用 []
方括号来访问一个项。我们通过使用运算符重载来实现这一点。
operator []
我们希望该运算符返回对我们的基项的引用。请记住,基项的类型是 TBase
。
//Operator Returning a reference to TBase TBase& operator [](int ItemKey) { return m_items[ItemKey]; }
我们的集合类现在完成了。请看下面的整个文件。
头文件
//TCollection.h #include <vector> using namespace std; template <class TBase> class TCollection { protected: //The Vector container that will hold the collection of Items vector<TBase> m_items; public: int Add(void) { //Create a new base item TBase BaseItem; //Add the item to the container m_items.push_back(BaseItem); //Return the position of the item within the container. //Zero Based return (m_items.size()-1); } //Function to return the memory address of a specific Item TBase* GetAddress(int ItemKey) { return &(m_items[ItemKey]); } //Remove a specific Item from the collection void Remove(int ItemKey) { //Remove the Item using the vector’s erase function m_items.erase(GetAddress(ItemKey)); } void Clear(void) //Clear the collection { m_items.clear(); } //Return the number of items in collection int Count(void) { return m_items.size(); //One Based } //Operator Returning a reference to TBase TBase& operator [](int ItemKey) { return m_items[ItemKey]; } };
测试集合类
我们通过创建一个包含我们 TCollection.h 文件的 winmain.cpp 文件来测试集合类。
#define WIN32_MEAN_AND_LEAN //Normal win32 headers #include <windows.h> #include <windowsx.h> //--------------------- //The collection class header #include "TCollection.h" //The string class #include <string> using namespace std; int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, char * cmdParam, int cmdShow) { TCollection<string> ColClass; //Create a collection of strings int i = ColClass.Add(); ColClass[i] = "Hallo"; MessageBox(NULL, ColClass[i].c_str(),"",MB_OK); return(0); }
从上面的代码可以看出,我创建了一个新的字符串集合,添加了一个项,然后访问了该项及其属性。我们现在拥有一个可以接受任何类型的集合类。毫不费力……
举个例子,如果我将 int 作为我的集合类
char buffer[20]; TCollection<int> ColClass2; int j = ColClass2.Add(); ColClass2[j] = 3; sprintf(buffer,"Item %d = %d",j, ColClass2 [j]); MessageBox(NULL,buffer,"",MB_OK);
待办事项
像本文前面所述,创建一个 CBoard
和 CButton
类。向棋盘添加九个按钮,设置每个按钮的属性,然后循环遍历每个按钮并显示其属性。