I'm pretty new to C++ and I'm trying to make an interactive virtual shop (not like with real money or anything, just something to practice coding, for possible use in a future game). So far I have defined the class and made it so that each object in the class is defined as fruit# where # is its id number (which is used in an array to define its name)
So basically at this point I have created the proper code to turn the user input into the id number of the fruit, but now I need a way to set the values of the fruit "select" to the values of the fruit that id belongs to.
Essentially, they type "banana," which I can use to arrive at the value 0, and the object "fruit0" corresponds to banana. So how do I get from 0 to fruit0? If this is confusing, let me know and I can try to explain better, but I already feel like I'm rambling...
Here's the (relevant parts of the) code:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
const int fruits=6;
//# of fruits
string names[fruits];
string s;
class fruit {
public:
float weight, price;
int id;
string name;
fruit (float a, float b, string c, int d)
{weight = a; price=b; name=c; names[d]=c;}
};
int main()
{
fruit fruit0 (.5,1,"banana",0);
fruit fruit1 (1.5,3,"pineapple",1);
fruit fruit2 (2,2.5,"coconut",2);
fruit fruit3 (1,1.5,"papaya",3);
fruit fruit4 (4,2,"watermelon",4);
fruit select (0,0,"\0",fruits);
//other, irrelevant code...
}
void ask()
{
cout<<"What would you like to buy? ";
getline (cin,s);
if (s=="select") {dontsell();}
for (i=0;i<fruits;i++)
{if (s==names[i]){select(i);}}
dontsell();
}
void select(int a)
{
//what goes here???
}
I suggest you use std::map<std::string, Fruit>.
You can use the map for storing fruits and their key phrases. It's sort of like a "codename" structure where one value is always associated with another, such as "Banana" to fruit1. Otherwise, I don't really see much of a problem with your question--it's a pretty simple problem which has nice solutions.
You could opt for std::vectors or something, but if you need double vectors that need to be linked by keyword or something, just use std::map.
void ask()
{
cout<<"What would you like to buy? ";
getline (cin,s);
if (s=="select") {dontsell();}
for (i=0;i<fruits;i++)
{
if (s==names[i])
{
// somehow indicate the selected fruit
}
}
dontsell();
}
If I understand correctly, you're asking for advice on how to indicate which fruit object is selected. There are many different ways to do this, but here's one: return the id of the fruit. You also need an array or something to allow you to get the actual fruit object from the id.
int ask() {
// ...
if (s == names[i]) {
return i;
}
// ...
// if nothing matches, return nothing:
return -1;
}
int main() {
fruit fruit_array[fruits] = {
fruit(.5, 1, "banana", 0),
fruit(1.5, 3, "pineapple", 1),
fruit(2, 2.5, "coconut", 2),
fruit(1, 1.5, "papaya", 3),
fruit(4, 2, "watermelon", 4)
};
int selected_id = ask();
if (id > 0) {
std::cout << "You chose " << fruit_array[selected_id].name << '\n';
} else {
std::cout << "You didn't choose anything I recognized.\n";
}
}
Of course, once you do this there are some other changes you would probably want to make. For example there's no reason to have separate arrays names and fruit_array. Here's an example of one way to avoid the duplicate representation of that data.
Related
I need to write a spell book and I have two ways to do it - use enum, or use std :: map, as it is easier for me to use enum. But I ran into a problem how to display my enum?
I want to make it so that I can display all these spells on the screen and ask the user which of these spells do you want to use?
for example:
enum Book {
Tornado,
FireBall,
etc,
};
I want it to be output to the console like this :
choose one:
1.Tornado
2.FireBall
how to output this,for example with using array,is it possible?
If you want to display the enum (Tornado, FireBall) instead of 1, 2 you can create a separate function doing that display
#include <iostream>
enum Book {
Tornado,
FireBall,
};
void yourFunction(const Book& book)
{
switch(book)
{
case Book::Tornado:
std::cout<<"Tornado"<<std::endl;
break;
case Book::FireBall:
std::cout<<"FireBall"<<std::endl;
break;
default:
break;
}
}
int main()
{
Book b=Book::FireBall;
yourFunction(b);
return 0;
}
The general problem described here is associating a known integer value with a text string. The solution can be as straightforward as this:
enum Book {
Tornado,
Fireball,
last_index // see below
};
static const char* names[] = {
"Tornado",
"Fireball"
};
To display the menu, just go through the enumerators:
for (int i = Tornado; i < last_index; ++i)
std::cout << (i + 1) << '.' << names[i] << '\n';
You can do this because enumerators start at 0 and increase by 1, that is, the value of Tornado is 0 and the value of Fireball is 1. The value of last_index is 2.
The reason for using last_index is to make it easier to maintain the code. If you add an enumerator that loop doesn't change:
enum Book {
Tornado,
Fireball,
GladHands,
last_index // see below
};
static const char* names[] = {
"Tornado",
"Fireball",
"Glad Hands"
};
With the added enumerator, the value of GladHands is 2 and the value of last_index is 3, so the original loop still works.
Note that this does not generate text from the name of the enumerator. The name of the enumerator has restrictions on it that the text version doesn't, so you really can't generate text in most cases. In particular, GladHands has no spaces, but its text version has one.
This might take a bit to explain.
I'm making a text-based game for a programming class. I'm attempting to describe the environment the player is currently in, based on their input.
First step:
if (playerChoice == 3) { //If they choose option 3, run the describe environment function
bool restart = CheckSurroundings(PlayerCharacter, ItemList, Map);
}
Next step:
static bool CheckSurroundings(Player &PlayerCharacter, vector <Item> &ItemList, vector<Area> &Map) {
cout << Map[PlayerCharacter.Position()].GetDescription() << endl;
//cut unimportant stuff out
return false;
}
What's above currently outputs a smiley face on my desktop computer, and printed an entirely different character when ran on my laptop.
"Map" is a vector of Area objects:
int mapSize = 17;
vector <Area> Map (mapSize);
SetupMapID(Map, itemList, mapSize);
The inclusion of the function SetupMapID is important. It's where I "set up" the map vector by giving all of the area objects inside the vector their name, description, and additional attributes. This is a preview of what it looks like:
static void SetupMapID(vector<Area> &Map, vector <Item> ItemList, int mapSize) {
Map[0].Name("The Mall Entrance Hallway");
Map[0].Description("The entrance to the mall has been blockaded with various benches, trash cans empty vending machines, and the occaisonal wood plank. This won't keep the zombies out for long.");
Map[0].Accessible(true);
}
Here is the actual area class header file (or, some of it, with what's unimportant cut out)
class Area {
private:
std::string areaName;
std::string areaDescription;
public:
std::string Name() { //GetName
return areaName;
}
void Name(std::string newName) { //SetName
areaName = newName;
}
//Area Description
std::string Description() { //GetDescription
return areaDescription;
}
void Description(std::string newDesc) { //SetDescription
areaDescription = newDesc;
}
};
EDIT: In case someone asks, I DO have a constructor set up, where description is given the string of "A".
Now that all of the context that should need to be given has been given, I can jump back up to the cout statement from above:
cout << Map[PlayerCharacter.Position()].Description() << endl;
Map, is as you saw, a vector of Area objects, and I'm looking to grab the Area object that the Player is currently in, which can be retrieved with PlayerCharacter.Position() (this returns 0 - 15). So "Map[PlayerCharacter.Position()]" gets that Area object. Then, after that. The function Description(), with no params, returns the object's description string. Nothing super complicated, but for reasons unknown to me, instead of returning the string it ought to be returning ("The entrance to the mall has been blockaded..."), it returns a random ASCII character (I think ASCII?). On my desktop computer, it always returns a smiley face.
This is where I'm stuck. Why is it returning a smiley face? The Name() function functions as intended (returns the area's "name" as a string), and everything associated with THAT is called stylistically the exact same.
Please help! I can work around it by just creating an array of strings and throwing the Area's # at it, but I would most prefer avoiding that.
I'm wondering if the problem has something to do with running out of space? My instructor thought it might have something to do with using reference variables, but I have absolutely no clue why Name() works but Description() doesn't.
I spent 5 minutes assembling your snippets (via copying and pasting) into an actual compilable and executable code snippet.
If I compile the below with gcc on Linux, I get the following output (copied and pasted straight from the console window):
The Mall Entrance Hallway
The entrance to the mall has been blockaded with various benches, trash cans empty vending machines, and the occaisonal wood plank. This won't keep the zombies out for long.
So it works, code is below. The broken part is not in what you showed us OR there's an issue with your compiler or environment, which I think is extremely unlikely but now you can just copy the below and test for yourself. I made some extremely simplifying assumptions on the parts you didn't show us, so you're going to have to share those or figure out why your outcome is different. My first suggestion would be to put your actual Player class and Position() function in place of mine. I wonder if perhaps your call to Position modifies the state of the internal member somehow so the first call (for Name) works but the second call doesn't. Just a thought.
#include <iostream>
#include <vector>
using namespace std;
class Area {
private:
std::string areaName;
std::string areaDescription;
public:
std::string Name() { //GetName
return areaName;
}
void Name(std::string newName) { //SetName
areaName = newName;
}
//Area Description
std::string Description() { //GetDescription
return areaDescription;
}
void Description(std::string newDesc) { //SetDescription
areaDescription = newDesc;
}
};
static void SetupMapID(vector<Area> &Map, int mapSize) {
Map[0].Name("The Mall Entrance Hallway");
Map[0].Description("The entrance to the mall has been blockaded with various benches, trash cans empty vending machines, and the occaisonal wood plank. This won't keep the zombies out for long.");
}
class Player {
public:
int Position() {
return 0;
}
};
int main()
{
int mapSize = 17;
vector <Area> Map (mapSize);
SetupMapID(Map, mapSize);
Player PlayerCharacter;
cout << Map[PlayerCharacter.Position()].Name() << endl;
cout << Map[PlayerCharacter.Position()].Description() << endl;
return 0;
}
I'm making a class-based inventory system using two classes: one for characters and one for items.
Code by Ryan Newell - NEW14136796 Uclan Student
(Need to put this in so plagarism monitors won't flag me for copying my own work)
Here's what I got so far.
///Code by Ryan Newell - NEW14136796 Runshaw College - Uclan
#include<iostream> //Base C++ required #
#include<string> //Allows input of strings
#include<iomanip> //Base C++ required #
#include <conio.h> //Getchar error workaround
#include <cstdlib> // Provides EXIT_SUCCESS
#include <fstream> // Allows output of txt files
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <utility>
#include <Windows.h>//ConsoleSleep
using namespace std;
class itemspell{
string itemname; //Name ((( what if items are the same name ? make difficult for finding statements ? maybe more char with same name item ?
string itemtype; // Spell/Weapon/Armour/Magic Misc?
string itemact; // What type of action does this item do ?
string itemdesc; // Some random ingame description
itemspell* inext; //The next pointer location
bool isspell; //Is Spell Boolean
bool isweapon; // Weapon
bool isarmour; // So on so forth
bool ismisc; // Misc
bool offensiveitem; //Offensive item
bool defensiveitem; // defensive item
bool passiveitem; // Passive effect
int damage;
int armour;
int magicbonus;
int magicresistance;
int cost;
void item_spellsearch(itemspell* ihead, itemspell* &ipast, itemspell* &icurrent)
{
string search;
if (ihead==NULL)
{
cout<<"There are no items on the list to search"<<endl;
}
else
{
cout<<"Enter the type item you are searching for :"<<endl;
getline(cin,search);
icurrent=ihead; //current pointer goes to -> header
cout<<icurrent<<" "<<search<<" "<<icurrent->itemtype<<endl;
while(icurrent!=NULL && search>icurrent->itemname)
{
cout<<"Item Type:"<<icurrent->itemtype<<" "<<cout<<icurrent->itemname<<endl;
ipast=icurrent; //Past = new current pointer
icurrent=icurrent->inext; //current pointer = next pointer
}
}
}
public:
itemspell()//Building a new item // -- Cannot put byref / by values in here remember, needs to be default constructor for some reason ??
{
cout<<"Enter Item Type: "<<endl;
getline(cin,itemtype);
cout<<"Enter Item Name: "<<endl;
getline(cin,itemname);
cout<<"Enter Item Description: "<<endl;
getline(cin,itemdesc);
cout<<"Enter Item Action :"<<endl;
getline(cin,itemact);
}
~itemspell()//Delete record output
{
cout<<"Item being deleted"<<endl;
Sleep(500);
cout<<"Item deleted"<<endl;
getch();
}
void additemspell(itemspell* &ihead) // Add record code
{
itemspell *icurrent;
itemspell *ipast;
itemspell *newitem;
newitem = new itemspell; // New itemspell
if (ihead == NULL || newitem->itemname<ihead->itemname) //If no header or itemname is null;
{
newitem->inext = ihead;
ihead = newitem;
}
else
{
icurrent= ihead;
while(icurrent !=NULL&&icurrent->itemname<newitem->itemname) // While the current char Does not equal NULL/"Nothing and charcurrent itemname = newitemitemname"
{
ipast=icurrent;
icurrent=icurrent->inext;
}
newitem->inext=icurrent; // Sets the next char to current and the past char to next to add in new record.
ipast->inext=newitem;
}
}
void deleteitemspell(itemspell* &ihead) /// Getting the address of the itemspell not the itemspell itself
{
itemspell *ipast=NULL, *icurrent=NULL;
item_spellsearch(ihead, ipast, icurrent);
if(ihead!=NULL)
if(icurrent==NULL)
{
cout<<"ERROR: No itemspell Found"<<endl;
Sleep(500);
cout<<"returning to menu... press enter"<<endl;
getch();
}
else
{
if (icurrent == ihead)
{
ihead = ihead->inext;
}
else
{
ipast->inext=icurrent->inext; //Resets the pointer and header's back to previous positions....
delete icurrent;// Calls the deletion of the itemspell entry.
cout<<"itemspell found was deleted press enter to confirm"<<endl;
getch();
}
}
}
class character
{
string forename;
string surname;
string nickname;
string race;
string alignment;
string alignment_type;
string character_class;
int Strength; //Strength
int Intelligence; //Magick 2
int Willpower; //Magick 1
int Endurance; //Health
int Agility; //Agility
int StartingWealth; //StartingWealth
character* char_itemp; // Character - Item pointer - Adress location of the characters items
character* char_next; // Next Pointer Value- Points to the location of the next person in the Dynamic Linked List
What I'm trying to do is when I create a new item, I want to be able to give that item to a character to use.
I know somewhere along the lines of I need to create a pointer value in the character class to point to the itemspell class but I am unsure what to do and could do with some help.
Essentially I want to get the character class to point to the item class when the item class is called from the constructor within the item class.
Please, if you can, don't give just code. Rather, please highlight areas where I should change and give suggestion examples. My degree program is strict about plagiarism.
Pseudo Code
When newitemspell created
get input charactername ()
:
if no current itemspell created for that character
add item to
character->charactername
else
add item to next pointer character->charactername
By looking at your code and looking at the descriptor of what you're trying to accomplish, why don't you just create an Inventory class to handle a users items? It should be able to handle 99% of anything you're wanting to do. Let me know if this example is anything like what you're trying to do.
To be completely honest, I have nary a clue what it is exactly you're trying to do in your code. As a previous user mentioned, "linking" two classes is a simple matter of giving the base class a variable of the required class. For example:
#include <vector> //I prefer to use vectors for just about any list of objects.
//It's just more convenient for me.
using std::vector;
class Inventory //A handler for all of your character's stuff.
{
private:
vector<object_class> objs; //To actually store an array of whatever objects
//you need to.
//Just some example functions to make the class useful.
public:
int MAX = -1; //The size limit for the inventory. This can be used as a useful
//statistic in the specific inventory, depending on how it's being
//used. My example shows the value at -1, which, at least for me,
//means that any maximum size checks being done won't bother it
//because I usually have a setting of -1 as being unlimited.
getItem(int slot); //Return item
removeItem(int slot) //Removing items
addItem(object_class object) //Adding items
}
This is just really simple programming from here. All you need to do is create variables with the type of Inventory. Any reference to an object_class is just a generic fill-in for the class type of whatever object you're wanting the Inventory to handle. This will most likely be a base class while you're using derivatives.
class Character //The character class with all kinds of stuff to needs to be handled
{
public:
Inventory items; //A regular inventory bag for items.
Inventory equip; //The items the character is currently using.
Inventory spells; //An alternate use for Inventory to be used as a handler for
//spell lists and other cool stuff.
}
And from here you should be able to understand what exactly is going on. Inventory isn't "linked" to Character. Character has three variables with the type Inventory and the Inventory class itself will handle all of the adding, removing, sorting and retrieving of items in its vector.
Now you can make everything work like so:
int main(int argc, char *argv[])
{
Character player;
Armor shield = new Armor(); //A dummy object
player.items.addItem(shield); //Assuming the Inventory is setup to handle Armor items.
//This will add the shield to the player's inventory.
player.items.MAX = 10; //Setting the maximum capacity of items to 10, obviously.
Armor A = player.items.getItem(0); //returns the piece of armor in the first spot in the vector.
}
I would normally write way more modular code for something like this, such as making Inventory a template class, but I digress. This was just to show you how to attach one class object to another.
I hope this was remotely like what you were searching for. If not, please try rewriting your question a little more specifically.
I wrote a program to find duplicate entry in a table. I am a beginner in C++, hence I don't know how this program is working efficient. Is there any other idea to write this program? Here I have 3 tables (2D Vector), that they are 1)aRecord_arr 2)mainTable and 3)idxTable. idxtable is use to identify the keys to check duplicate entry. aRecord_arr table to be add in maintable. If it is already exist in maintable, it will show the error "Duplicate Entry". So Check this program, and give your suggestions.
typedef vector<string> rec_t;
typedef vector<rec_t> tab_t;
typedef vector<int> cn_t;
int main()
{
tab_t aRecord_arr= { {"a","apple","fruit"},
{"b","banana","fruit"} };
tab_t mainTable = { {"o","orange","fruit"},
{"p","pineapple","fruit"},
{"b","banana","fruit"},
{"m","melon","fruit"},
{"a","apple","fruit"},
{"g","guava","fruit"} };
tab_t idxTable = { {"code","k"},
{"name","k"},
{"category","n"}};
size_t Num_aRecords = aRecord_arr.size();
int idxSize = idxTable.size();
int mainSize = mainTable.size();
rec_t r1;
rec_t r2;
tab_t t1,t2;
cn_t idx;
for(int i=0;i<idxSize;i++)
{
if(idxTable[i][1]=="k")
{
idx.push_back(i);
}
}
for(size_t j=0;j<Num_aRecords;j++)
{
for(unsigned int id=0;id<idx.size();id++)
{
r1.push_back(aRecord_arr[j][idx[id]]);
}
t1.push_back(std::move(r1));
}
for(int j=0;j<mainSize;j++)
{
for(unsigned int id=0;id<idx.size();id++)
{
r2.push_back(mainTable[j][idx[id]]);
}
t2.push_back(std::move(r2));
}
for(size_t i=0;i<t1.size();i++)
{
for(size_t j=0;j<t2.size();j++)
{
if(t1[i]==t2[j])
{
cout<<"Duplicate Entry"<<endl;
exit(0);
}
}
}
}
If you want to avoid duplicate entries in an array, you should consider using a std::setinstead.
What you want is probably a std::map or a std::set
Don't reinvent the wheel, the STL is full of goodies.
You seem to be rooted in a weakly typed language - but C++ is strongly typed.
You will 'pay' the disadvantage of strong typing almost no matter what you do, but you almost painstakingly avoid the advantage.
Let me start with the field that always says 'fruit' - my suggestion is to make this an enum, like:
enum PlantType { fruit, veggie };
Second, you have a vector that always contain 3 strings, all with the same meaning. this seems to be a job for a struct, like:
struct Post {
PlantType kind;
char firstchar;
string name;
// possibly other characteristics
};
the 'firstchar' is probably premature optimization, but lets keep that for now.
Now you want to add a new Post, to an existing vector of Posts, like:
vector<Post> mainDB;
bool AddOne( const Post& p )
{
for( auto& pp : mainDB )
if( pp.name == p.name )
return false;
mainDB.push_back(p);
return true;
}
Now you can use it like:
if( ! AddOne( Post{ fruit, 'b', "banana" } ) )
cerr << "duplicate entry";
If you need speed (at the cost of memory), switch your mainDB to map, like:
map<string,Post> mainDB;
bool AddOne( const Post& p )
{
if( mainDB.find(p.name) != mainDB.end() )
return false;
mainDB[p.name]=p;
return true;
}
this also makes it easier (and faster) to find and use a specific post, like
cout << "the fruit is called " << mainDB["banana"].name ;
beware that the above will cause a runtime error if the post dont exists
As you can see, firstchar was never used, and could be omitted. std::map
has a hash-function-specialization for string keys, and it will probably be
orders of magnitude faster than anything you or I could whip up by hand.
All of the above assumed inclusion of the correct headers, and
using namespace std;
if you dont like using namespace, prepend std:: to all the right places
hope it helps :)
At the moment I am using a vector to store pointers to the object every time one is made, but that feels a little silly. There's probably a better way, but I haven't found it.
What I'm doing: Example usage:
The problem:
If I want to retrieve a certain Date I have to go over all items in the vector to see if RecPaymentsStack.stackDate matches the date the user requested.
The RecPaymentStack is actually completely useless at the moment because what I should be doing, is, when adding a new item, checking if a "RecPaymentStack.stackDate" has already been made for the new item's Date property, and if so add the new pointer to "RecPayments" to an array of pointers inside the "RecPaymentStack" object. But how?
I'm probably unnecessarily complicating things (something I do a lot) so an explenation on how something like this should be done would be very nice.
Detailed info: (in case I was being too vague)
The below example is supposed to resemble a calendar that can hold certain items (RecPayments) and those items are grouped by their date (RecPaymentsStack).
struct RecPayments
{
std::string name;
Date* date;
float cost;
};
struct RecPaymentsStack
{
Date* stackDate; //This stack's date
RecPayments * thePaymentItem; //Hold pointer to the actual item
};
And here's how I'm currently storing them
std::vector<RecPaymentsStack*> RecPaymentsVector; //This vector will hold pointers to all the Recurring Payments
void addRecurring(std::string theDate,std::string theName,float theCost)
{
//New recurring payment
RecPayments * newPaymentItem = new RecPayments;
//Set recurring payment properties
newPaymentItem->name = theName;
newPaymentItem->date = new Date(stringToChar(theDate));
newPaymentItem->cost = theCost;
//Add recurring payment to stack
RecPaymentsStack * addToStack = new RecPaymentsStack;
addToStack->stackDate = new Date(stringToChar(theDate));
addToStack->thePaymentItem = newPaymentItem;
//Add pointer to RecPaymentsStack to vector
RecPaymentsVector.push_back(addToStack);
}
So to retrieve the items for a given date, I am currently going over all pointers in the vector to see if the "stackDate" property matches the requested date, and if so I use the "thePaymentItem" property to show the actual item.
void getItemsNow(Date requestedDate)
{
std::cout << "Showing Dates for " << requestedDate << std::endl;
unsigned int i;
for(i=0;i<RecPaymentsVector.size();i++) //Go over all items in vector
{
Date dateInVector(*RecPaymentsVector[i]->stackDate); //Get the date from the vector
if(dateInVector == requestedDate) //See if Date matches what the user requested
{
//Date matched, show user the item properties.
std::cout << "Date: " << dateInVector <<
" has name: " << RecPaymentsVector[i]->thePaymentItem->name <<
" and price " << RecPaymentsVector[i]->thePaymentItem->cost <<
std::endl;
}
}
}
3 problems with this:
Going over all items in the vector is highly inefficient if I only
need a couple of pointers
The RecPaymentStack is actually completely useless at the moment because what I should be doing, is, when adding a new item, checking if a "RecPaymentStack.stackDate" has already been made for the new item's Date property, and if so add the new pointer to "RecPayments" to an array of pointers inside the "RecPaymentStack" object. But how?
All of this feels extremely silly to begin with.. there's probably a much easier/professional way to do this but I can't find out what, probably because I'm still thinking like a PHPer.
So the general idea here is that I end up doing something like (silly example)
for each RecPaymentsStack->stackDate //For each unique Date, show it's children items.
{
cout << "The Date is " CurrentRecPaymentsStack->stackDate and it holds the following items:
for each CurrentRecPaymentsStack->thePaymentItem //This would now be an array of pointers
{
cout << "item name " CurrentRecPaymentsStack->thePaymentItem->name << " with cost " << CurrentRecPaymentsStack->thePaymentItem->cost << endl;
}
}
Which would basically go over all the unique "RecPaymentsStack" objects (unique determined by it's "Date" property) and for each Date it would then show it's "children" from the RecPayments struct.
And there has to be some way to search for a particular date without having to go over all the available ones.
Rather than using a vector to manage your items, you should replace your RecPaymentsStack instance with a std::multimap. The key type is your Date structure, the value type is RecPayments (which I would change to the singular form RecPayment). Small example (untested):
typedef std::multimap<Date, RecPayment> RecPaymentsByDateMap;
typedef std::pair<RecPaymentsByDateMap::iterator,
RecPaymentsByDateMap::iterator>
RecPaymentsByDateMapIters;
RecPaymentsByDateMap payments_by_date;
RecPaymentsByDateMapIters findByDate(Date date) {
return payments_by_date.equal_range(date);
}
...
// find all payments with the given date
RecPaymentsByDateMapIters iters = findByDate(...);
for (RecPaymentsByDateMap::iterator it = iters.first;
it != iters.second;
++it)
{
std::cout << "Payment " << it->second.name << std::endl;
}
I might design it like this -- this is just a loose idea, details should be adjusted according to your requirements:
#include <deque>
#include <map>
#include <string>
struct RecPayment
{
std::string name;
Date date;
float cost;
};
struct RecPaymentsStack
{
Date stackDate;
std::deque<RecPayment> thePaymentItem;
bool operator<(RecPaymentsStack const & rhs) const
{
return stackDate < rhs.stackDate;
}
explicit RecPaymentsStack(Date const & d) : stackDate(d) { }
};
typedef std::multimap<RecPaymentsStack> PaymentsCollection;
Now you can insert elements:
PaymentsCollection payments;
{
auto it = payments.emplace(Date("..."));
it->thePaymentItem.emplace_back(Payment{name1, date1, cost1});
it->thePaymentItem.emplace_back(Payment{name2, date2, cost2});
it->thePaymentItem.emplace_back(Payment{name3, date3, cost3});
}