我是否正确创建了对象数组?C++
Am I creating my object arrays correctly? C++
我正在尝试创建一个程序,该程序最多可存储50名玩家及其获胜次数。即一种用途可以用于跟踪运动队和他们赢得的比赛数量或其他什么。然而,我在更改球员得分时遇到了一个问题。我是C++的初学者,你可能会从我的代码中看出这一点。然而,我已经从对编码一无所知,到在大约一周内完成了三个不同的教程,并制作了几个非常简单的命令行程序。感谢所有关于编码技巧以及如何使scoreEdit((函数工作的帮助!请查收附件中的播放器类、scoreEdit((函数和我的主函数。
// for case 1. class that the scoreEdit() function uses!
class players
{
public:
void setName(string x)
{
name = x;
}
void addWin()
{
amtOfWins += 1;
}
void setWins(int x)
{
amtOfWins=x;
}
string getName()
{
return name;
}
int getWins()
{
return amtOfWins;
}
private:
string name;
int amtOfWins;
};
|
// for case 1. reads the file then stores each name in it's own player object and associates that with the amt of wins. Then rewrites all names and amtofwins to the file
void scoreEdit()
{
ifstream istats("stats.txt");
ofstream ostats("stats.txt");
if (istats.is_open() && ostats.is_open())
{
players player[50];
string tempName;
int tempWins;
while (istats >> tempName >> tempWins)
{
// reads in the name and amt of wins, and stores them in player object variables.
for (int x=0; x<50; x++)
{
player[x].setName(tempName);
player[x].setWins(tempWins);
}
}
string winner;
cout << "Who won?" << endl;
cin >> winner;
for (int x=0; x<50; x++)
{
if (player[x].getName()==winner)
{
player[x].addWin();
cout << "Ok. " << player[x].getName() << " has gained 1 point." << endl;
}
}
int x=0;
while (ostats << player[x].getName() << ' ' << player[x].getWins())
{
x++;
}
}
else
{
cout << "Quitting program. Stats could not be opened." << endl;
}
}
|
// main function
int main()
{
int x=0;
cout << "n";
while (x==0) // not really sure if this is needed. Loops until case 4 or 5. Probably didn't need to use x. Oh well.
{
switch (choices())
{
case 0: // clears file
{
string decision;
cout << "ARE YOU SURE? This will wipe all data. (Type yes or no)n" << endl;
cin >> decision;
if (decision=="yes")
{
clearStats();
cout << "STATS ARE WIPED.n" << endl;
break;
}
else if (decision=="no")
{
cout << "Ok, stats will not be wiped.n" << endl;
break;
}
else
{
cout << "Your input was not recognized. Stats will not be wiped.n" << endl;
break;
}
}
case 1: // they want to add 1 to a player's score
{
scoreEdit();
break;
}
case 2: // they want to add a player
{
string name;
cout << "What is their name?" << endl;
cin >> name;
addPlayer(name);
break;
}
case 3: // they want to view the stats
{
readStats();
break;
}
case 4: // they want to quit. Simple! :)
{
return 0;
}
default: // means they did not input 1 2 3 or 4
{
cout << "Invalid input. Quitting program. Try again." << endl;
return 1;
}
}
}
}
编辑:附言,我所有的其他功能/案例都起作用。我就是好像找不出这个有什么问题!我需要使用矢量吗?
第二版:谢谢你的建议。现在,有没有办法检查文件是否还有数据要输入?现在,它输入线条,这样无论发生什么,都有50个玩家对象。我可以制作一个类似int linesLeftInFile
的变量并使用for (int x=0; x<linesLefInFile; x++)
吗?抱歉问了这么多初学者的问题。
您试图打开文件两次,一次用于读取,一次写入,但同时打开。
...
ifstream istats("stats.txt");
ofstream ostats("stats.txt");
if (istats.is_open() && ostats.is_open())
...
当你打开它进行写作时,就像你一样,文件内容会被删除。读取该文件的尝试将失败,从而造成大混乱。
先打开你的流只读,然后关闭流,然后打开写并放入结果。或者,您可以考虑一个具有读写功能的fstream。
顺便说一句,对于你的玩家类来说,预见一个默认的构造函数是一个很好的做法
本质上有两个方面:
A(
我是否正确创建了对象数组?C++
它与持久性实现和实例生命周期问题有关,以及
B(
编辑:[…]我需要使用矢量吗?[…]现在,它输入线条,这样无论发生什么,都有50个玩家对象。
这与分配和容器有关。
这两个方面当然是交叉的,例如像std::vector
这样的容器对它所承载的实例的生命周期有很大的影响。
然而,这两个方面与提供给应用程序的控制器的功能几乎没有关系,该功能尚未通过main()
中的循环来实现。
因此,处理这些方面应该委托给一个类,该类将它们与应用程序的其余部分分离。
让我们把那个类称为PlayerDataBase
。
PlayerDataBase将容纳一个容器。但是哪个?
Complile时间固定大小的阵列,如
Player c_arra_players[50];
// or
std::array<Player,50> std_array_players;
反正都是假的;存在一个任意实体计数的外部基准,该外部基准支配多重性;因此容器必须支持运行时重新调整大小。
std::vector<Player>
使用起来简单明了,但需要进行
for (int x=0; x<50; x++) {
if (player[x].getName()==winner)
{
player[x].addWin();
cout << "Ok. " << player[x].getName() << " has gained 1 point." << endl;
}
}
它在像std::vector
这样的顺序容器上具有O(n(复杂性,而在像std::map
这样的关联容器(使用名称作为关键字(上的相同搜索将是O(log(n((,如果std::unordereded_map’将与完美散列函数一起使用,则大约为O(1(。
另一方面,添加,尤其是重命名播放器(用例:修复缺口中的拼写错误(对于关联容器来说将比顺序容器更昂贵。
特别是对于C++学习者来说,使用不同的内部存储表示可能会很有趣,因此PlayerDataBase
可以是一个带有容器模板参数的模板。
应用程序中应该只有一个PlayerDataBase
实例,并且控制器应该具有对该实例的单个访问点;因此,它意味着是一个单例。
ifstream/ofstream/fstream
问题可以通过PlayerDataBase
非常简单地处理——它的(私有(ctor读取或创建并读取ifstream中的统计文件,该文件在ctor完成后关闭。
数据的持久化由flush()
函数完成,该函数使用_file_name
成员打开ofstream
,进行写入,并在flush
终止时关闭该流。
///
///@brief modified singleton pattern
///
template<template<typename...> class Cont>
class PlayerDataBase : private players_container_adaptor<Cont> {
private:
using Traits = players_container_traits<Cont>;
public: // type interface
using container_type = typename Traits::players_container_type;
using Base = players_container_adaptor<Cont>;
struct no_such_player : public std::runtime_error {
no_such_player(const std::string& msg) : std::runtime_error(msg) {}
};
public: // creation interface
static PlayerDataBase& instance(const std::string& file_name = ::FILE_NAME)
throw (std::runtime_error) {
// automatically dtored
static PlayerDataBase _instance_(file_name); // throws
return _instance_;
}
public: // behaviour interface
void flush () const throw(std::ios::failure);
void addWin(const std::string& key) throw (no_such_player);
private: // types and function name resolution
using Adaptor = Base;
using Adaptor::getPlayer; // throws std::runtime_error
// container specific lookup,
using Adaptor::make_inserter; // std::copy(..,..,,make_inserter(Cont & c));
using Adaptor::emplace; // dispatches to container_specific emplace
using _asset_type = typename Traits::asset_type;
constexpr static auto BAD_AND_FAIL = std::ios::badbit | std::ios::failbit;
constexpr static auto BAD_ONLY = std::ios::badbit;
struct no_stats_file : public std::runtime_error {
no_stats_file(const std::string& msg) : std::runtime_error(msg) {}
};
private: // lifecycle interface
PlayerDataBase(const std::string&) throw (std::runtime_error);
~PlayerDataBase() noexcept;
// This is a singleton
PlayerDataBase(const PlayerDataBase&) = delete;
PlayerDataBase(PlayerDataBase&&) = delete;
PlayerDataBase& operator=(PlayerDataBase&&) = delete;
PlayerDataBase& operator=(const PlayerDataBase&) = delete;
PlayerDataBase& operator=(PlayerDataBase&) = delete;
private: // helpers
void create_data_file() const throw(std::ios::failure);
private: // state
container_type _players;
std::string _file_name;
}; // class PlayerDataBase
#include "playerdatabase.inl"
所需的特征和适配器模板可能如下所示:
template<template<typename...> class C> struct players_container_traits {};
// [...]
template<> struct players_container_traits<std::map> {
using players_container_type = std::map<std::string, Player>;
using player_ckv_type = players_container_type::value_type;
using player_kv_type = std::pair<std::string, Player>;
using asset_type = player_kv_type;
}; // struct player_container_traits<std::map>
// [...]
template<template<typename...> class C> struct players_container_adaptor{};
// [...]
template<> struct players_container_adaptor<std::map> {
using Traits = players_container_traits<std::map>;
using players_map_type = Traits::players_container_type;
static void post_ctor(players_map_type&) {
/* nop */
}
static Player& getPlayer(players_map_type& m, const std::string& key)
throw (std::runtime_error) {
auto it = m.find(key);
if (it == m.end())
throw std::runtime_error(key + " unknown");
return it->second;
} // addWin(players_map_t&,...)
static auto make_inserter(players_map_type& m)
-> decltype(std::inserter(m, m.begin())) {
return std::inserter(m, m.begin());
}
template<typename... Targs, typename K, typename... Args>
static void emplace(std::map<Targs...>& m, K&& k, Args&&... args) {
K _k = k;
m.emplace(std::piecewise_construct,
std::forward_as_tuple(_k),
std::forward_as_tuple(k, args...));
}
}; // template<> struct players_container_adaptor<std::map>
我假设业务类将被重命名为Player
,并为<<
>>' for
ostream resp.
istream的输出获得一堆(noexcept(运算符和一些相关的自定义运算符。
黑客快乐!
2014年7月20日补遗无论如何,我看不出有太多理由进行随机序列访问,因此如果仍然使用序列容器(由于查找复杂性,我不主张这样做(,那么std::list
将更合适;这节省了std::vector
可能遭受的完全且昂贵的重新分配的成本。
- 将对象数组的引用传递给函数
- 如何使用Visual Studio 2017在C++中为参数化对象数组使用唯一指针
- 在c++中尝试对对象数组进行排序时,出现std:bad_alloc错误
- 类对象数组的问题会导致崩溃
- Arduino C++在构造函数中用参数声明对象数组
- 使用对象数组对 SFML 进行动画处理
- C++ 对象数组堆栈溢出
- 如何将对象数组作为参数传递给模板
- 使用向量初始化参数化构造函数的对象数组
- 如何初始化对象数组?
- C++创建对象数组
- 在对象数组中搜索字符串并返回相应值的函数
- 有没有办法使用该类的构造函数初始化另一个类的私有部分内的对象数组?
- 如何在运行时在对象数组中动态追加新对象C++并打印它们
- 为什么我在声明对象数组时不能使用 -> 运算符?
- 编译时生成应在构造函数中创建的非 constexpr 对象数组
- 使用 C++ 创建对象数组
- 对象数组打印空白字符串
- 重载运算符 [] 用于从对象数组中给出特定索引
- 如何在 C++ 中使用提升属性树从 JSON 文件中读取对象数组