I have a class which made of a ints and strings, but I also have a vector inside that class. I have to read the records from a file and then after parsing each line, put the info in my vector of class. I have to get the basic package information like ID and name and then add the services which are offered with that package, so I can have 10 records that are from one package but they are different in type of services. For now I am trying to work out putting the data in each package and access the data from each element, but when I am trying to get the data from the vector inside the class, my compiled file crashes. It also prints out the 1233 and foo, but not the test. Any ideas why is that?
int main()
{
vector<package> packs;
package pack;
pack.ID = 1233;
pack.name = "foo";
packs.push_back(pack);
pack.putData("test",12);
cout << packs[0].name << endl;
cout << packs[0].ID << endl;
cout << packs[0].bservice[0].serviceID << endl; //[b]Crashes in this line[/b]
return 0;
}
Defined class is:
class package
{
public:
class aservice
{
public:
int serviceID;
string othername;
};
int ID;
string name;
vector<aservice> bservice;
void putData(string name1, int serviceID1)
{
aservice obj;
obj.serviceID = serviceID1;
obj.othername = name1;
bservice.push_back(obj);
}
};
Here you make a copy of pack when you push_back into the vector:
packs.push_back(pack);
And here you access pack, not the copy stored in your vector
pack.putData("test",12);
So the bservice vector you are trying to access is actually empty, which is why your code crashes when you try to access it here:
cout << patients[0].bservice[0].serviceID << endl; // patients[0].bservice is empty!!!
You can avoid this by pushing back after the call to putData:
vector<package> packs;
package pack;
pack.ID = 1233;
pack.name = "foo";
pack.putData("test",12);
packs.push_back(pack);
You can also avoid it by not trying to access a vector without first checking whether it is empty.
Ideally you should strive to design classes than can be constructed into a useful state, as opposed to default constructing them and adding data step by step via setters. This is particularly important if the data are inter-related and the class must maintain invariants.
packs.push_back(pack);
Is going to push a copy of pack into your vector. You will therefore have two specific instances : if you call putData on one of those, the other one will not be modified itself !
Therefore, when writing
patients[0].bservice[0]
your application crashes because you did not putData inside patients[0], only inside pack - which is, once again, a different object.
You should modify your vector so it stores pointers to package's, and push the adress of pack inside.
pack.push_back(pack);
Assuming the first pack is actually packs, this pushes a copy of pack onto the vector.
pack.putData("test",12);
This modifies the local variable pack, but not the copy you pushed onto the vector. That still contains an empty bservice vector.
cout << patients[0].bservice[0].serviceID << endl;
Assuming that patients is actually packs, this erroneously attempts to read from the empty bservice vector.
You either want to call putData before packs.push_back(pack), or call it on packs.back() rather than the local pack.
Try this:
#include <vector>
#include <iostream>
using namespace std;
class package
{
public:
package(int inID, const string& inName ) : ID(inID), name(inName)
{
}
void putData(string name1, int serviceID1)
{
aservice obj;
obj.serviceID = serviceID1;
obj.othername = name1;
bservice.push_back(obj);
}
void Print() const
{
cout << ID << endl;
cout << name << endl;
vector<aservice>::const_iterator iter;
iter = bservice.begin();
for (; iter != bservice.end(); ++iter)
{
cout << iter->serviceID << " " << iter->othername << endl;
}
}
private:
class aservice
{
public:
aservice() {};
int serviceID;
string othername;
};
int ID;
string name;
vector<aservice> bservice;
};
typedef vector<package> PackContainer;
typedef vector<package>::iterator PackContainerIterator;
typedef vector<package>::const_iterator PackContainerConstIterator;
void PrintAll(const PackContainer& packs)
{
PackContainerConstIterator iter = packs.begin();
for (; iter != packs.end(); ++iter)
{
iter->Print();
}
}
int main()
{
PackContainer packs;
package pack( 1233, "foo");
pack.putData("test",12);
packs.push_back(pack);
PrintAll(packs);
return 0;
}
Related
Im just starting to learn C++ and i would like to acess and modify a vector of objects that have different variable types. I have only been able to create the vector, but cant do anything with it. How can i acess and modify it?
This is the code i have created so far:
class Person {
private: string name; int id;
public:
Person(string x, int y) { name = x; id = y; };
~Person();
};
int main()
{
vector<vector<Person>> v4;
}
To access objects stored in the vector you have different operators and methods such as at() or operator[] For more details check https://www.cplusplus.com/reference/vector/vector/
Since you want to learn C++, I assume you do not know what exactly to ask, so let me help you
Your code example lacks further things, besides accessing the objects in the vector:
Since name and id are private you cannot access them.
Your destructor has no implementation
You created a vector of vectors of Persons. I assume you want just a vector.
Your question regarding multiple types in one vector: This is not easily possible. Depending on what you want, you need multiple vectors, or need to combine your data (e.g. through std::pair, or you need to work with interfaces and inheritance.
Your vector is empty
Let me construct something to give you a hint on where to continue:
#include <iostream>
#include <string>
#include <vector>
class Person {
private:
std::string name;
int id;
public:
Person(std::string x, int y) { name = x; id = y; };
// ~Person(); //This is not needed, since your class currently does not need any special handling during destruction
// You need to be able to access name and id to be able to do something with them, for example print it
std::string getName() const {
// be aware that this creates a copy of name. Thus changes to the returned string will not be reflected in the Person object.
// Another option would be returning a reference (std::string&), but that I leave for you to research yourself
return name;
}
int getId() const {
// same as for the name applies
return id;
}
// This allows us to change the id of a Person
void setId(int newId) {
id = newId;
}
};
int main()
{
// Lets create a Person first:
Person p ("John", 1); // Please note that the string literal here will be used to construct an std::string on the fly and then store it in name of p
// Create a second Person:
Person p2 ("Jim", 2);
// Create a vector and add the persons to it
std::vector<Person> v;
v.push_back(p);
v.push_back(p2);
// Print out the contents of the vector
for (auto& pers : v) {
std::cout << "Person " << pers.getName() << " has id " << pers.getId() << std::endl;
}
// Now change the id of the second person in the vector to 5 (note that indexes start at 0)
v.at(1).setId(5);
// Print again
for (auto& pers : v) {
std::cout << "Person " << pers.getName() << " has id " << pers.getId() << std::endl;
}
}
To play around with it: https://godbolt.org/z/8dfEoa
I hope that helps you getting started.
I am having trouble figuring out why this is not compiling. This is just the basic class declaration, constructor/destructor and other functions are left out. Message is also properly defined somewhere else.
#include <vector>
#include <map>
using namespace std;
class SmartCarrier {
map<string, vector <Message *>> accounts_map;
void SearchMessage() const;
};
When I try to assign m_iter with m_iter = accounts_map.find(account) I get the error no operator "=" matches these operands. I double checked to make sure the map iterator was the same type as the actual map which it is. I'm not sure what is incorrect.
void SmartCarrier::SearchMessage() const {
string account;
map<string, vector<Message *>>::iterator m_iter;
cout << "Enter an account: ";
cin >> account;
try {
m_iter = accounts_map.find(account);
if (m_iter != accounts_map.end) {
//code to display account information
} else {
throw 'e';
}
} catch (char e) {
cout << "Error: Account not found\n";
}
}
SearchMessage() is declared as const, so its this parameter is pointing at a const SmartCarrier object, so its accounts_map member is also const. When find() is called on a const map, it returns a const_iterator instead of an iterator.
Also, accounts_map.end needs to be accounts_map.end() instead.
Also, using an exception the way you are is just wasted overhead that you can (and should) get rid of.
Try this:
void SmartCarrier::SearchMessage() const {
string account;
cout << "Enter an account: ";
cin >> account;
map<string, vector<Message *>>::const_iterator m_iter = accounts_map.find(account);
if (m_iter != accounts_map.end()) {
//code to display account information
} else {
cout << "Error: Account not found\n";
}
}
If you are using C++11 or later, consider using auto instead of const_iterator explicitly, that would also fix the error:
auto m_iter = accounts_map.find(account);
Hi I need some clarification on some code since google did not help nor did any of my C++ books. Ok I have a base class,which I derived 2 other classes, but I did not post the code for them here since they don't have anything to do with my question:
ifndef BASEBALLPLAYER_H
#define BASEBALLPLAYER_H
#include <iostream>
using namespace std;
class BaseBallPlayer{ //abstract class meaning no instance can be made for it, which is why we access it via derived classes
//data members
protected:
string name;
int height;
int weight;
public:
BaseBallPlayer();
BaseBallPlayer(string nam, int wight, int hight);
string get_Name();
virtual void print_player()=0; //
virtual void load_player(ifstream & read) = 0; //
virtual ~BaseBallPlayer();
};
Then an ArrayList.h file:
#ifndef ARRAY_LIST_H
#define ARRAY_LIST_H
#include <string>
using namespace std;
const static int MAX_INIT = 99;
template <class elemType>
class ArrayList {
private:
int n_element;
elemType * data;
public:
~ArrayList();
ArrayList(int n = MAX_INIT);
ArrayList(const ArrayList<elemType> &);
const ArrayList<elemType> & operator=(const ArrayList<elemType> &);
void MakeEmpty();
bool IsFull() const;
int LengthIs() const;
void RetrieveItem(elemType &, bool&);
void InsertItem(elemType);
void DeleteItem(elemType);
void ResetList();
bool IsLastItem();
void GetNextItem(elemType &);
};
Now my question lies in this new class, its a standalone class, that I made in the PlayerDatabase.h file:
#ifndef PLAYERDATABASE_H
#define PLAYERDATABASE_H
#include <iostream>
#include "BaseBallPlayer.h"
#include "ArrayList.h"
using namespace std;
class PlayerDatabase{
private:
ArrayList<BaseBallPlayer *> teamArrayList; // I do NOT Understand what this means?
public:
};
#endif
I DO NOT understand what the private member in my PlayerDatabse.h file means or entails? And what can I do with it? My instructor told us to usethat template with a pointer but I didn't have a chance to ask what it does/mean?
So I'm not exactly sure what you end goal is here, but let me take a quick guess at what you might be trying to do:
So you mentioned you have 2 subclasses of BaseBallPlayer, let's say they are MajorLeaguePlayer and MinorLeagePlayer This private Array list teamArrayList can be used to hold any combinations of your base class (BaseBallPlayer -- in your case MajorLeaguePlayer and MinorLeaguePlayer).
You usually want to leave this teamArrayList private so that it will only be safely modified by your public methods. So for example you might want to have a constructor for PlayerDatabase that takes an argument of ArrayList<BaseBallPlayer *>
PlayerDatabase(ArrayList<BaseBallPlayer *> players) {
// set the private teamArray list in the constructor
teamArrayList = players;
}
or you might want to sort the teamArray list based off of one of the properties in the base class BaseBallPlayer
// or another one sorting for weight or name
void sortPlayerListByHeight() {
// sort the private team array list
teamArrayList = ... // sort by height
}
Maybe you want to get the number of players in the list, or find the first or last player in the list. In general it's good practice to use public methods to access/modify private data members (i.e. teamArrayList)
int numberOfPlayersInList() {
return teamArrayList.LengthIs();
}
BaseBallPlayer getFirstPlayerInList() {
return teamArrayList.RetrieveItem.... // get the first item in the list
}
Then from another class you could construct some of your subclass objects and construct your player database:
ArrayList<BaseBallPlayer *> playerList = new ArrayList<>();
playerList.add(new MinorLeagePlayer("minorName", 180,70);
playerList.add(new MajorLeaguePlayer("majorName", 200, 72);
PlayerDatabase db = new PlayerDatabase(playerList);
// now you can do some operations on the PlayerDatabase knowing that the list will contain all objects that can use methods from the Base Class (`BaseBallPlayer`)
db.getFirstPlayerInList().print_player(); // method from your base class implemented in your subclasses
int numberOfPlayers = db.numberOfPlayersInList();
// do something with the number of players in the list
This is pseudo code, but hopefully it will help you get the idea.
Edit related to our comments:
ArrayList<BaseBallPlayer *> *playerList = new ArrayList<BaseBallPlayer *>();
MinorLeaguePlayer *aPlayer = new MinorLeaguePlayer();
playerList->InsertItem(aPlayer);
I've included a couple of simple cout statements in the ArrayList constructor, the MinorLeaguePlayer constructor, and the InsertItem method to output some information when they are called (I'm assuming you already have implementations of these methods):
ArrayList constructor: n_element = n;
cout << "Constructing the arrayList, n_element = " << n_element << endl;
MinorLeaguePlayer constructor: cout << "Constructing a minor league player" << endl;
InsertItem method: cout << "Inserting an item into the ArrayList" << endl;
Here's the output after building and running the above code:
Constructing the arrayList, n_element = 99
Constructing a minor league player
Inserting an item into the ArrayList
Edit 2 related to further comments:
Methods which take a reference to the elemType
Example:
// this will basically just going to "hold" the BaseBallPlayer fetched
// from GetNextItem
BaseBallPlayer *bPlayer;
playerList->GetNextItem(bPlayer);
cout << "Weight after fetching from list = " << bPlayer->weight << endl;
The implementation of GetNextItem is going to look something like this:
void ArrayList<elemType>::GetNextItem(elemType& player) {
// implementation to get the next item in the array list
player = //... set the "NextItem" to the BaseBallPlayer reference we passed into this method
}
Edit 3: print_player() polymorphism:
MinorLeaguePlayer *minPlayer = new MinorLeaguePlayer();
MinorLeaguePlayer *min2Player = new MinorLeaguePlayer();
MajorLeaguePlayer *majPlayer = new MajorLeaguePlayer();
MajorLeaguePlayer *maj2Player = new MajorLeaguePlayer();
playerList->InsertItem(minPlayer);
playerList->InsertItem(min2Player);
playerList->InsertItem(majPlayer);
playerList->InsertItem(maj2Player);
BaseBallPlayer *fetchedPlayer;
for (int i = 0; i < 4; i++) {
playerList->GetNextItem(fetchedPlayer);
fetchedPlayer->print_player();
}
Notice that you have to get the reference to the fetchedPlayer prior to calling the print_player() method on it
playerList->GetNextItem(fetchedPlayer);
fetchedPlayer->print_player();
This is because of the way your GetNextItem method is structured to place the reference to the nextItem in the passed in BaseBallPlayer.
Here's another example where the method would return the BaseBallPlayer instead of setting it by reference:
method stub (in ArrayList):
elemType getNextItemReturn();
for loop:
for (int i = 0; i < 4; i++) {
playerList->getNextItemReturn()->print_player();
}
Here's a link to a quick discussion asking which is more efficient:
Which is more efficient: Return a value vs. Pass by reference?
And the output with the example cout statements:
Constructing the arrayList, n_element = 99
Inserting an item into the ArrayList
Inserting an item into the ArrayList
Inserting an item into the ArrayList
Inserting an item into the ArrayList
Printing From MINOR League Player
Player Name: MinorLeagueName Weight = 22
Printing From MINOR League Player
Player Name: MinorLeagueName Weight = 22
Printing From MAJOR League Player
Player Name: MajorLeaguePlayer Weight = 33
Printing From MAJOR League Player
Player Name: MajorLeaguePlayer Weight = 33
The mock implementations of print_player():
void MinorLeaguePlayer::print_player() {
cout << "Printing From MINOR League Player" << endl;
cout << "Player Name: " << name << " Weight = " << weight << endl;
}
void MajorLeaguePlayer::print_player() {
cout << "Printing From MAJOR League Player" << endl;
cout << "Player Name: " << name << " Weight = " << weight << endl;
}
teamArrayList is a list of pointers to BaseBallPlayer objects. By using pointers, it can by polymorphic -- the pointers can point to any class derived from BaseBallPlayer.
This is the common way to use an abstract base class. You can then use it to call the methods in the BaseBallPlayer class, and the implementations in the appropriate derived classes will be used.
I am new to C++ and am not able to find the answer. This is the code I want to write:
#include <iostream>
using namespace std;
class Employee{
private:
string name;
string gender;
public:
void display();
void update(string);
Employee(string a, string b){
name = a;
gender = b;
};
~Employee(){};
};
void Employee::display(void){
cout << "Name: " << name << endl;
cout << "Gender: " << gender << endl;
}
void Employee::update(string a){
/*
a function that updates either the
name element or gender element
based on which element it is used by.
*/
}
int main(){
Employee employee1 ("Joe","Male");
Employee employee2 ("Jon","Male");
employee1.display();
employee2.display();
employee1.name.update("Mary"); // This is what I want to do: Same function
employee2.gender.update("Female"); // for different elements of same type
employee1.display();
employee2.display();
return 0;
}
How do I go about doing this?
I thought about function overloading but both elements are of the same type. I do not want to pass any extra values and make the code look crappy. Any ideas? Thank you.
Use setters and getters like this:
void Employee::setName(const string &a) {
this->_name = a; // validate or whatever you need to do
}
const string &Employee::name() const {
return this->_name;
}
void Employee::setGender(const string &a) {
// ....
}
Usage as one would expect
employee1.setName("Mary");
employee2.setGender("Female");
The basic_string class already implements a 'setter':
employee1.name.assign("Mary");
employee2.gender.assign("Female");
If you want to access name and gender like you have written in your question, you need to make both public, as #sop correctly pointed out.
Is there any practical way to get objects to work with maps? (I don't really know much about maps so sorry if this is a bad question). I'm interested in using a map for an inventory system that will contain item objects. An item object has a name, description, and money value. The key would be the item's name, and the linking variable would be the the quantity of items I have for that particular item.
And if a map doesn't work, does anyone have a good alternative to this type of system? I need something keeping track of the quantity of each type of item I have.
The C++ standard library template map is just a storage container so it can definitely be used with objects. The map will take your object as its templated argument parameter.
A map would work well for your inventory system. Use something like:
#include <pair>
#include <map>
#include <string>
#include <iostream>
class Item {
public:
Item(void) {}
~Item(void) {}
Item(std::string new_name) {
my_name=new_name;
}
void setName(std::string new_name) {
my_name= new_name;
}
std::string getName(void) {
return my_name;
}
private:
std::string my_name;
};
class Item_Manager {
public:
Item_Manager(void) {}
~Item_Manager(void) {}
void addItem(Item * my_item, int num_items) {
my_item_counts.insert( std::pair<std::string,int>(Item.getName(),num_items) );
}
int getNumItems(std::string my_item_name) {
return my_item_counters[my_item_name];
}
private:
std::map<std::string, int> my_item_counts;
};
main () {
Item * test_item = new Item("chips");
Item * test_item2 = new Item("gum");
Item_Manager * my_manager = new Item_Manager();
my_manager->addItem(test_item, 5);
my_manager->addItem(test_item2,10);
std::cout << "I have " << my_manager->getNumItems(test_item->getName())
<< " " << test_item->getName() << " and "
<< my_manager->getNumItems(test_item2->getName())
<< " " << test_item2->getName() << std::endl;
delete test_item;
delete test_item2;
delete my_manager;
}
Here's a reference on the stdlib map and its functions:
http://www.cplusplus.com/reference/stl/map/
Look at the function pages for examples of how to iterate through/index a map, etc.
If you're talking about std::map, it's a template which can work with any type of object, as long as a way to compare objects for ordering is provided. Since your key (the name) is a string, it will work right out of the box with std::map
struct Item
{
std::string description;
int value;
};
int main()
{
// associate item names with an item/quantity pair
std::map<std::string, std::pair<Item, int> > itemmap;
}
I need something keeping track of the quantity of each type of item I have.
How about std::vector<std::pair<Item, int> >?