该程序允许您从商店卖家那里购买(和出售)多达5种商品,并且还具有货币系统。
主要
// Shop.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "Player.h"
#include "ShopKeeper.h"
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
int main()
{
Player player; //The player
ShopKeeper shopKeeper; //The shop keeper
int responce; //Menu navigation
std::cout << "Greetings " << player.GetName() << ". Feel free to browse my wares." << "\n";
std::cout << "1: Purchase Items. 2: Sell Items. 3: List Your Items. 4: Show Gold. 5: Exit" << "\n";
do
{
std::cin >> responce;
switch (responce)
{
case 1:
shopKeeper.PurchaseItem(player);
break;
case 2:
shopKeeper.SellItem(player);
break;
case 3:
player.ListInventory();
break;
case 4:
std::cout << "You have " << player.GetGold() << " gold coins." << "\n";
break;
case 5:
std::cout << "Thank you for shopping." << "\n";
break;
default:
std::cout << "Please enter valid data." << "\n";
std::cout << "1: Purchase Items. 2: Sell Items. 3: List Your Items. 4: Show Gold. 5: Exit" << "\n";
}
std::cout << "1: Purchase Items. 2: Sell Items. 3: List Your Items. 4: Show Gold. 5: Exit" << "\n";
} while (responce != 5);
/*
//This works
player.AddItem("Mace", 30);
player.ListInventory();
std::cout << player.GetGold();
*/
//Keep window open
std::string barn;
std::cin >> barn;
return 0;
}
ShopKeeper.h
#pragma once
#include "Player.h"
#include <string>
class ShopKeeper
{
private:
public:
void PurchaseItem(Player& player); //Shop keeper has player buy items from them
void SellItem(Player& player); //Shop keeper sells item to player
ShopKeeper();
~ShopKeeper();
};
ShopKeeper.cpp
#include "stdafx.h"
#include "ShopKeeper.h"
#include "Player.h"
#include <iostream>
//Player purchases item from shop keeper
void ShopKeeper::PurchaseItem(Player& player)
{
//Player player;
int responce = 0; //Menu navigation
std::cout << "1: Mace - 30 gold. 2: Bow - 50 gold. 3: Boots - 10 gold. 4: Bearskin - 75 gold. 5: Helmet - 25 gold." << "\n";
do
{
std::cin >> responce;
switch (responce)
{
case 1:
player.AddItem("Mace", 30);
break;
case 2:
player.AddItem("Bow", 50);
break;
case 3:
player.AddItem("Boots", 10);
break;
case 4:
player.AddItem("Bearskin", 75);
break;
case 5:
player.AddItem("Helmet", 25);
break;
default:
std::cout << "Please enter valid data." << "\n";
std::cout << "1: Mace - 30 gold. 2: Bow - 50 gold. 3: Boots - 10 gold. 4: Bearskin - 75 gold. 5: Helmet - 25 gold." << "\n";
}
} while (responce > 5 || responce < 1);
}
//Shop keeper sells item to player
void ShopKeeper::SellItem(Player& player)
{
//Player player;
int responce = 0;
player.ListInventory();
if (responce < player.GetNumbOfItems())
{
std::cin >> responce;
switch (responce)
{
case 1:
player.SellItem(0, 20);
break;
case 2:
player.SellItem(1, 20);
break;
case 3:
player.SellItem(2, 20);
break;
case 4:
player.SellItem(3, 20);
break;
case 5:
player.SellItem(4, 20);
break;
default:
std::cout << "Please enter valid data." << "\n";
player.ListInventory();
}
}
else
{
std::cout << "Item doesn't exist.";
}
}
ShopKeeper::ShopKeeper()
{
}
ShopKeeper::~ShopKeeper()
{
}
Player.h
#pragma once
#include <vector>
class Player
{
private:
const int maxNumbItems = 5; //Maximum number of items that inventory can store
int goldCoins = 150, //Amount of gold coins the player has
numbOfItems = 0; //Number of con-current items player holds
std::vector<std::string> inventory; //Players inventory
std::string name = "Gorrex"; //Players name
public:
std::string GetName(); //Get the players name
std::string AddItem(std::string item, int itemPrice); // Add item to players inventory
void Player::SellItem(int itemNum, int itemPrice); //Sell item
bool IsInventoryFull(); //Check to see if players inventory is full
int InventoryCapacity(); //Get capacity of inventory
int GetGold(); //Get players gold
void ListInventory();
int GetNumbOfItems();
Player();
~Player();
};
Player.cpp
#include "stdafx.h"
#include "Player.h"
#include <iostream>
#include <ostream>
#include <string>
//Get the players name
std::string Player::GetName()
{
return name;
}
//Add item to players inventory
std::string Player::AddItem(std::string item, int itemPrice)
{
//Is players inventory not full?
if (IsInventoryFull())
{
std::cout << "Inventory is full.";
}
else
{
//Can player afford item?
if (goldCoins >= itemPrice)
{
goldCoins -= itemPrice;
numbOfItems++;
std::cout << "You have purchased " << item << "." << "\n";
inventory.push_back(item); //Add item to inventory
return item;
}
//If player cant afford item
else
{
std::cout << "You cannot afford this item." << "\n";
}
}
}
void Player::SellItem(int itemNum, int itemPrice)
{
char responce;
std::cout << "Are you sure you want to sell: " << inventory[itemNum] << "? 'y' - Yes. 'n' - No." << "\n";
std::cin >> responce;
switch (responce)
{
case 'y':
numbOfItems++;
goldCoins += itemPrice;
inventory.erase(inventory.begin() + itemNum);
break;
case 'n':
std::cout << "That is ok." << "\n";
break;
default:
std::cout << "Please enter correct data." << "\n";
}
}
//Check to see if players inventory is full
bool Player::IsInventoryFull()
{
//If players inventory isnt full
if (numbOfItems < maxNumbItems)
{
return false;
}
//If players inventory is full
else
{
return true;
}
}
//Return size of players inventory
int Player::InventoryCapacity()
{
return inventory.size();
}
//Get the players gold
int Player::GetGold()
{
return goldCoins;
}
//List the players inventory
void Player::ListInventory()
{
int itemNumb = 0; //item number in menu
for (int i = 0; i < inventory.size(); i++)
{
itemNumb++;
std::cout << itemNumb << ": " << inventory[i] << "\n";
}
/* //If inventory is empty
if (inventory.empty())
{
std::cout << "inventory is empty" << "\n";
}*/
}
int Player::GetNumbOfItems()
{
return numbOfItems;
}
Player::Player()
{
}
Player::~Player()
{
}
#1 楼
以下是一些可以帮助您改进代码的事情。请确保您已具备所有必需的
#include
s Player.h使用
std::string
但未使用#include <string>
。另外,请仔细考虑哪些#include
是接口的一部分(并属于.h
文件),哪些是实现的一部分。不要在成员声明中包括类名
Player.h文件包含以下行:
void Player::SellItem(int itemNum, int itemPrice); //Sell item
它不应包含类名,因此应改为:
void SellItem(int itemNum, int itemPrice); //Sell item
一般可移植性
如果省略仅Windows包含文件
#include "stdafx.h"
,则可以将此代码移植。 注意带符号和无符号
在
Player::ListInventory
例程和其他例程中,代码会将int i
与从size_t
返回的inventory.size()
进行比较,但是size_t
是未签名的,而int
是签。而是将两个变量都声明为size_t
类型。始终将
return
设置为适当的值您的
Player:AddItem()
例程具有控制路径,该例程导致其结束时没有return
输入任何std::string
值。这是一个错误,应予以解决。简化逻辑
代码中的某些地方可以大大简化。例如,当前代码包含以下内容:
//Check to see if players inventory is full
bool Player::IsInventoryFull()
{
//If players inventory isnt full
if (numbOfItems < maxNumbItems)
{
return false;
}
//If players inventory is full
else
{
return true;
}
}
可以这样写:
bool Player::IsInventoryFull()
{
return numbOfItems >= maxNumbItems;
}
在可行的地方使用const
当前的
Player::GetName()
例程不会(也不应该)修改基础对象,因此应将其声明为const
:std::string GetName() const; //Get the players name
其他许多不修改底层对象的例程也是如此。
析构函数通常应该是虚拟的
如果我们想从您现有的一个类(例如Player类)中派生一个类,则我们希望将析构函数设为虚拟。请参阅此问题以获取关于原因的更完整说明。类,因此您应该忽略它们,而只是让编译器自动生成它们。
考虑分离输入和输出
现在,许多功能都会发出提示,从用户那里读取内容,然后更新相关对象的内部状态。更具模块化(并且可能更易于维护)的方法会将I / O部分与对象内部状态的更新分开。例如,请参见“模型-视图-控制器”设计模式。
消除“幻数”
代码中有一些数字,例如
5
和20
具有在其特定上下文中具有特定含义。通过使用诸如NUMBER_OF_MENU_ITEMS
或OFFERED_PRICE
之类的命名常量,该程序将变得更易于阅读和维护。对于常量仅对特定对象有意义的情况,请考虑将该常量作为对象的一部分。在许多地方使用菜单对象
在您的代码中,您有类似于菜单的内容。您的代码提供了两个选项,然后要求用户根据输入数字选择一个。与其在许多地方重复该代码,不如将其通用。实际上只有提示字符串会发生变化,但是呈现选择和要求输入的基本逻辑都是相同的。
更好地清理用户输入
如果我在菜单提示之一中输入字符串而不是数字,该程序将永远循环。与直接输入
int
相比,更安全的方法是输入字符串,然后像std::stoi
一样将其转换为整数。 忽略
return 0
当C ++程序到达
main
的末尾时,编译器将自动生成代码以返回0,因此没有理由将return 0;
明确地放在main
的末尾。 />评论
\ $ \ begingroup \ $
stdafx.h没有特定于Windows的窗口,它只是一个头文件,其中包含最常用的#includes来加快使用预编译头的编译速度。它由GCC,Clang和MSVC支持。 stdafx.h中可能包含一两个特定的窗口,例如tchar.h或targetver.h,但是在跨平台时可以将其删除。
\ $ \ endgroup \ $
– Johnbot
15年12月22日在9:11
\ $ \ begingroup \ $
您能详细说说它不应该包含类名吗?为什么呢
\ $ \ endgroup \ $
–lukas.pukenis
15年12月22日在10:20
\ $ \ begingroup \ $
有两个原因不包含类名。第一个是它根本就没有必要,因为它已经在类声明中了;第二个是出于可读性和一致性,因为您的其他方法都不包含类名。
\ $ \ endgroup \ $
–爱德华
15年12月22日在13:01
\ $ \ begingroup \ $
@Johnbot:更简单的是删除文件。我的Linux机器上没有stdafx.h,是的,我知道它的用途以及MSVC生成它的原因。但是,对于这样的小型项目,编译速度不太可能有太大差异,否则会妨碍可移植性。
\ $ \ endgroup \ $
–爱德华
15年12月24日在2:45
#2 楼
我知道使用注释是个人喜好,但要考虑的是在可能的情况下用描述性变量和函数名称替换它们。Player.cpp中的示例: />
//Check to see if players inventory is full
bool Player::IsInventoryFull();
您在这里选择了一个好的描述性函数名称,因此此注释可能不会为一般可读性增加很多价值。
相关阅读:
http://elegantcode.com/2010/04/18/eliminate-comments-the-road-to-clarity/
#3 楼
我相信您的代码中有一个错误:void Player::SellItem(int itemNum, int itemPrice)
{
char responce;
std::cout << "Are you sure you want to sell: " << inventory[itemNum] << "? 'y' - Yes. 'n' - No." << "\n";
std::cin >> responce;
switch (responce)
{
case 'y':
numbOfItems++; // <-- bug here
goldCoins += itemPrice;
inventory.erase(inventory.begin() + itemNum);
break;
case 'n':
std::cout << "That is ok." << "\n";
break;
default:
std::cout << "Please enter correct data." << "\n";
}
}
如果将其卖给店主,为什么要增加商品数量?该数字应递减:
--numbOfItems;
实际上,您甚至根本不需要
numbOfItems
,因为所拥有的项数实质上是inventory
向量的大小。这使您不必在购买/出售功能中增加/减少此值,并且还简化了IsInventoryFull()
函数的逻辑:bool IsInventoryFull() const
{
return inventory.size() < maxNumbItems;
}
InventoryCapacity()
错误。当我们谈论某物的容量时,通常是在谈论某物当前可以容纳的最大尺寸。在您的函数中,您要返回的是库存的当前大小,而不是最大大小,即maxNumbItems
。可以将其更改为以下内容:int InventoryCapacity() const
{
return maxNumbItems;
}
int getNumbOfItems() const
{
return inventory.size();
}
此外,由于您正在限制建造中玩家的库存大小,因此我们可以为我们保留该空间提前清点库存:
Player()
{
inventory.reserve(maxNumbOfItems);
}
最后,在您的
AddItem
函数中,不需要按值传递string
(因为这会复制它)。节省不必要的开销,并通过const引用传递。而且,不需要分支else
。它只是增加了另一个级别的不必要的缩进。您也没有该函数所有分支的有效返回string
。这些应该添加://Add item to players inventory
std::string Player::AddItem(const std::string &item, int itemPrice)
{
//Is players inventory not full?
if (IsInventoryFull())
{
std::cout << "Inventory is full.";
return "";
}
//Can player afford item?
if (goldCoins >= itemPrice)
{
goldCoins -= itemPrice;
numbOfItems++;
std::cout << "You have purchased " << item << "." << "\n";
inventory.push_back(item); //Add item to inventory
return item;
}
//If player cant afford item
std::cout << "You cannot afford this item." << "\n";
return ""
}
编辑:
您的评论似乎也不一致:
void PurchaseItem(Player& player); //Shop keeper has player buy items from them
void SellItem(Player& player); //Shop keeper sells item to player
当店主让玩家从他们那里购买物品时,他实际上就是在向玩家出售物品。因此,从店主的角度来看,如果玩家正在出售物品,那么他就是在购买物品。相反,如果玩家正在购买物品,则将其出售给玩家。这些令人困惑的评论可能是我突出显示该错误的原因。正如上面提到的,您的函数名称很好,因此我将省略注释。
评论
欢迎来到代码审查!在第一个问题上做得很好。不修改对象状态的成员函数应为const。 (例如,简单的get函数应为const)。