一个问题

在这些笔记中,我将开发一个c++程序来解决一个基于CMSC 250期末考试问题的问题。问题是建立一个简单的系统来管理电子市场中的交易。在这个问题中,交易者将向中央清算所提交交易请求。为简单起见,我们假设在这个市场中只有一种商品交易,并且不考虑价格。交易员将提交购买或出售特定数量的相关商品的请求,系统只需将买家与卖家进行匹配,并生成交易列表。

在程序中,我将在这些注释中描述买入和卖出指令将以包含买入和卖出指令列表的文本文件的形式出现。每个订单包括下订单的交易者的id号以及他们想要购买或出售的单位数量。下面是一个典型的输入文件的例子:

买入105 250卖出333 100卖出409 500买入632 400卖出375 100

系统将匹配买家和卖家,并发出第二个文本文件,其中包含应该进行的赢博体育交易的列表。下面是上面输入示例的输出文件:

333卖100套到105 409卖150套到105 409卖350套到632 375卖50套到632

项目的源代码

以下是包含此示例完整源代码的归档文件。

order类

构造解决方案的第一步是在c++中构造一个简单的类来表示顺序。这个类存储交易者的名字和他们想要交易的单位数量。订单类不包含有关这是买入还是卖出订单的信息-系统将通过将买入和卖出订单放在单独的列表中来记录该信息。

下面是order类的c++类声明:

类订单{私有:std::字符串交易员;int数量;public: Order(std::string name, int amount) {trader = name;Quantity =数量;} std::string getName(){返回交易者;} int getAmount(){返回数量;}无效reduceAmount(int amt){数量-= amt;}};

这个类声明出现在一个c++头文件Order.h中。

创建和处理对象

一旦构造了一个类声明,就可以开始处理Order对象了。c++有两种不同的系统用于创建对象和与对象交互。在第一个系统中,我们以普通变量的形式创建对象。下面是一个例子:

订单示例(“乔”,200);example.reduceAmount (100);

在这种方法中,我们使用一种特殊的语法来声明和初始化名为example的Order对象。上面第一个语句中的语法同时声明了一个Order类型的变量示例,并调用Order类的构造函数,用交易者名称和数量初始化该对象。一旦我们初始化了对象,我们就可以通过使用点方法调用语法调用对象上的方法来与它交互。

第二个处理对象的系统使用指针变量和new操作符:

Order *example = new Order("Joe",200);例子——> reduceAmount (100);

上面的第一个语句有两个部分:变量声明和初始化。变量声明部分,

订单*例子;

声明一个名为example的变量,它的类型是“指向顺序的指针”。指针是一种携带位置信息的变量。在本例中,示例变量将存储我们想要与之交互的Order对象的地址。使用c++的new操作符初始化指针变量,构造一个Order类型的新对象。new操作符返回一个指向新创建对象的指针,这是为我们创建对象的副作用。

example = new Order("Joe",200);

一旦我们创建了一个对象并获得了指向它的指针,我们将通过指针变量与对象进行交互。指针通过c++解引用操作符*支持一个重要的解引用操作。对指向对象的指针解引用使我们可以访问对象本身,因此可以使用通常的点表示法调用其方法:

(*) .reduceAmount (100);

由于在通过指针访问的对象上调用方法在c++中是一种常见的场景,因此该语言提供了一种更方便的语法等效方法。表达式

例子——> reduceAmount (100);

是一个更方便的等价形式。

最后,当处理完用new创建的对象后,需要使用delete操作符使该对象消失。

删除示例;

这将释放对象占用的空间,使该空间可用于程序中的其他目的。

队列类

在我们的程序中,我们需要的下一件事是用某种方式创建一个买卖订单对象的列表。为此,我将介绍另一个类,它将实现一个可以存储订单的简单线性数据结构。

该类是一个队列类。队列是一种线性数据结构,它支持两种操作,一种是将新项目放在队列末尾的enqueue操作,另一种是将项目从队列前端移除的dequeue操作。

队列结构通常实现为由指针连接在一起的节点集合。下面的图片说明了这种安排。

每个Node对象包含一些数据(在本例中是一个指向Order对象的指针)和一个指向链中前一个Node的指针。Queue对象本身包含两个指针,一个指向队列头部的Node,一个指向队列尾部的Node。

下面是设置Queue和Node类的类声明。

模板<typename T>类节点{公共:节点<T>*链接;T数据;节点(T项){link = nullptr;Data = item;} T getData(){返回数据;}};模板<typename T> class Queue {private: Node<T>* head;节点< T > *尾巴;public: Queue(){头=尾= nullptr;} //在队列尾部添加一个新项void enqueue(T item) {if (head == nullptr) {head = tail = new Node<T>(item);} else {Node<T>* newNode = newNode <T>(item);tail->link = newNode;tail = newNode;}} //删除队列头部的项目void dequeue() {if (head == nullptr)返回;节点<T>* toRemove = head;Head = Head ->链接;如果(头部== nullptr)尾部= nullptr;删除toRemove;} bool isEmpty(){返回头部== nullptr;} //返回队列T前面的数据项front(){返回head->数据;}};

这些类声明出现在一个名为Queue.h的头文件中。

为了使Queue类更加灵活,我们使用c++模板机制使这两个类都成为模板类。模板类包含一个或多个类型的占位符。在本例中,我们使用占位符T表示存储在队列节点中的数据类型。为了使一个类成为模板类,我们放置了符号

模板<typename T

在类声明的开始处。

在实例化Queue时,使用模板表示法指定占位符类型t应该使用的类型。在本赢博体育程序中,我们希望创建存储指向Order对象的指针的Queue对象,因此将使用该语法

队列<订单* > buyOrders;

声明Queue对象,将T替换为具体类型Order*,意思是“指向Order的指针”。

市场类

随着Order和Queue类的创建,我们现在有了解决做市问题的赢博体育元素。现在我们引入一个Market类,它将负责存储订单并运行订单匹配算法。

下面是这个Market类的类声明。

类Market {private: Queue<Order*> buyOrders;队列<订单* > sellOrders;public: Market() {} void addBuyOrder(std::string trader, int qty) {buyOrders。enqueue(新订单(交易员,数量));}无效addSellOrder(std::string trader, int qty) {sellOrders。enqueue(新订单(交易员,数量));}无效clearTrades(std::string fileName);};

这个类声明出现在一个名为Market.h的文件中。注意,这个类缺少它的一个方法clearTrades方法的代码。如果一个方法的代码在类声明中占用了太多的空间,c++允许我们在类声明中简单地列出该方法。该方法的实际代码随后出现在一个单独的文件Market.cpp中。以下是缺失方法的代码,因为它出现在单独的文件中:

无效市场::clearTrades(std::string fileName) {ofstream out;out.open(文件名);while (!buyOrders.isEmpty() && !sellOrders.isEmpty()) {Order* buy = buyOrders.front();Order* sell = sellOrders.front();int toBuy = buy->getAmount();int toSell = sell->getAmount();if (toBuy > toSell) {out << sell->getName() << " sells " << toSell << " units to " << buy->getName() << endl;买- > reduceAmount(出去);sellOrders.dequeue ();删除销售;} else if (toBuy == toSell) {out << sell->getName() << " sells " << toSell << " units to " << buy->getName() << endl;buyOrders.dequeue ();删除购买;sellOrders.dequeue ();删除销售;} else {out << sell->getName() << " sells " << toBuy << " units to " << buy->getName() << endl;buyOrders.dequeue ();删除购买;销售- > reduceAmount(买);}} out.close();}

出现在方法代码开头的::符号表明这是Market类中clearTrades方法的代码。

主要功能

使这个示例工作所需的最后一件事是main函数。该函数的代码出现在文件main.cpp中:

Void main() {ifstream in;in.open(“orders.txt”);字符串类型,名称;int数量;市场市场;While (in >> kind >> name >> qty) {if (kind == "buy") market。addBuyOrder(名称、数量);其他市场。addSellOrder(名称、数量);} in.close ();market.clearTrades(“trades.txt”);}

这里的代码打开包含订单信息的文本文件并读取订单。每个订单都有一个种类、一个交易商名称和一个数量,因此我们可以通过执行以下操作来读取单个订单的详细信息

In >> kind >> name >>数量

因为我们事先不知道文件中有多少个订单,所以我们在while循环中执行读取代码。我们使用了一个有点特殊的结构,它使用读取代码作为while循环的测试。这种方法利用了这样一个事实,即读取代码不仅从文件中读取数据:它还有一个副作用。对读取代码求值将返回有关读取是否成功的信息。如果读取成功,则读取表达式的计算结果为true,导致我们对循环体中的代码求值。当到达文件末尾并且读取失败时,读取表达式产生一个副作用值,计算结果为false,导致我们退出while循环。