Finding a classmember in a vector of other class members - c++

I have the classes Team and Player. Every Team member has an object vector playerlist with his players stored in. Every player now has some attributes like ID. Now i want to transfer a Player to a Team . So i created a function for this.
First i want to findout if the Player b maybe is already a member of Team a, in which case a message should be printed out. But i failed in writing a function which does this.
Here is my try(the search starts in the if loop, where i want to find out if Player b is member of Team a)
#include <vector>
#include <string>
#include <iostream>
using namespace std;
class Player
{
public:
private:
};
class Team
{
public:
vector<Player> getplayerlist(){
return playerlist;
}
string getteamname(){
return teamname;
}
void playerbuy(Team a, Player b)
{
vector<Player> playerlist;
playerlist = a.getplayerlist();
if (find(playerlist.begin(), playerlist.end(), 5) != playerlist.end()) {
}
else {
cout << "This player is not member of " << a.getteamname();
}
}
private:
vector<Player> playerlist;
string teamname;
};
int main()
{
return 0;
}
I got the error C2678: binary '==' : no operator found which takes a left-hand operand of type 'Player' (or there is no acceptable conversion). I figured out i comes from the line
if (find(playerlist.begin(), playerlist.end(), 5) != playerlist.end())
The =! playerlist.end() seems to be wrong there. This part of the code is some copy of another code so i don't know what it does. What should i put in there instead ?
And what does the 5 means ?

The error is giving you a good hint: you need to implement an equality operator for class Player. That is what std::find uses to determine if an element has been found.
Alternatively, you can use std::find_if with a custom unary predicate.

Related

Making a vector of superclass type that can store subclass objects

So I started a small little project to work on while I am learning. Basically, what I'm trying to do is a small "game" which I plan to build on as I learn new things.
Here is a brief description and my problem.
Basically, I want to assign various Hero types to a player based on their choice.
I made a base class "Hero" with only a HP parameter so far. After that, I made 2 derived classes from Hero, HeroType1, HeroType2 which will have specific abilities and so on.
I decided on storing various hero types in std::vector<Hero*> Heroes. Basically, I start my "game" by calling initializeHeroes function which, depending on the player choice creates a new object of type NewHero1 or NewHero2 and stores it an the vector mentioned before. The thing is, no matter what I tried so far, I can't access derived member functions when I want to use them later, only those of the Hero class.
What feels like a good solution: declare global variables player1, player2 and assign to them after players choose the HeroType. However, I can't do that because the data type has to be known before compiling. Sorry if this is a stupid and basic question, my knowledge is still very limited and that is why I am asking for some hints here.
I'd kindly like to ask on how would you approach this, I know it is a very simple issue, but I'm still a beginner and I'm trying to figure out the best way to solve this. Thanks in advance.
If you would like to call a member function from a element from std::vector<Hero*> Heroes and you know somehow that this element points to a Hero2-type, then you could create a new temporary variable Hero2 * tmpPtr and set this variable to the element whose memberfunction you want to call (tmpPtr = Heroes[i]). Then you should be able to call a memberfunction like this: tmpPtr->hero2Memberfuncion().
Full code:
#include <iostream>
#include <vector>
class SomeClass
{
public:
void a() {
std::cout << "a" << std::endl;
}
};
class AnotherClass : public SomeClass
{
public:
void b() {
std::cout << "b" << std::endl;
}
};
void main() {
std::vector<SomeClass *> vec;
AnotherClass v;
vec.push_back(&v);
AnotherClass * tmpPtr = (AnotherClass *)vec[0];
tmpPtr->b(); //Output: "b"
}
However if you want for example loop through the whole vector and for every element run a memberfunction that has the same name but the body of that function differs depending on to what Hero-type the element points, then you may want to use virtual functions. Example:
#include <iostream>
#include <vector>
class SomeClass
{
public:
virtual void a() {
std::cout << "from SomeClass" << std::endl;
}
};
class AnotherClass : public SomeClass
{
public:
void a() {
std::cout << "from AnotherClass" << std::endl;
}
};
void main() {
std::vector<SomeClass *> vec;
AnotherClass v1;
vec.push_back(&v1);
vec[0]->a(); //Output: "from AnotherClass"
SomeClass v2;
vec.push_back(&v2);
vec[1]->a(); //Output: "from SomeClass"
}

Filing a vector outside of a function in a class

Fairly simple question here, whats the best way to fill a vector outside of a function in a class .cpp file? currently i'm attempting the following which is not working:
std::vector<Player> midfielder(8);
midfielder.at(0) = Midfielder("Default ",0,"Midfielder");
midfielder.at(1) = Midfielder("David Armitage ",1,"Midfielder");
midfielder.at(2) = Midfielder("Tom Rockliff ",2,"Midfielder");
midfielder.at(3) = Midfielder("Gary Ablett ",3,"Midfielder");
midfielder.at(4) = Midfielder("Dyson Heppel ",4,"Midfielder");
midfielder.at(5) = Midfielder("Scott Pendlebury",5,"Midfielder");
midfielder.at(6) = Midfielder("Michael Barlow ",6,"Midfielder");
midfielder.at(7) = Midfielder("Jack Steven ",7,"Midfielder");
To provide context, 'Midfielder' is a class that inherits from the 'Player' class.
TeamManagment.h
#ifndef TEAMMANAGEMENT_H
#define TEAMMANAGEMENT_H
#include <vector>
#include "Player.h"
#include "Midfielder.h"
#include <string>
class TeamManagement
{
public:
TeamManagement();
void Display_Players();
};
#endif // TEAMMANAGEMENT_H
TeamManagement.cpp
#include <iostream>
#include <string>
#include <vector>
#include "Player.h"
#include "Midfielder.h"
#include "TeamManagement.h"
using namespace std;
TeamManagement::TeamManagement()
{
}
std::vector<Player> midfielder(8);
//errors start occurring on line below: 'midfielder' does not name a type
midfielder.at(0) = Midfielder("Default ",0,"Midfielder");
midfielder.at(1) = Midfielder("David Armitage ",1,"Midfielder");
midfielder.at(2) = Midfielder("Tom Rockliff ",2,"Midfielder");
midfielder.at(3) = Midfielder("Gary Ablett ",3,"Midfielder");
midfielder.at(4) = Midfielder("Dyson Heppel ",4,"Midfielder");
midfielder.at(5) = Midfielder("Scott Pendlebury",5,"Midfielder");
midfielder.at(6) = Midfielder("Michael Barlow ",6,"Midfielder");
midfielder.at(7) = Midfielder("Jack Steven ",7,"Midfielder");
//errors stop occurring here
void TeamManagement::Display_Players(){
cout<<"Position Name ID"<<endl;
for (int i=1;i<8;i++)
{
cout<<midfielder[i].Player_Details()<<" "<<midfielder[i].Get_player_id()<<endl;
}
}
The first problem is that you cannot perform assignment like that outside of a function. You must use construction or initialization.
With C++98 you cannot populate/initialize a vector outside of a function.
With C++11/14 you can populate one using initializer syntax:
#include <iostream>
#include <vector>
struct Thing {
int m_i, m_j;
Thing(int i, int j) : m_i(i), m_j(j) {}
};
std::vector<Thing> things {
{ 1, 2 }, { 2, 3 }
};
int main() {
std::cout << "things[0].m_j = " << things[0].m_j << '\n';
}
But std::vector won't like you trying to put "Midfielder"s into a vector of Player. Lets use an SSCCE to reconstruct the damage you're doing:
#include <iostream>
struct Base {
int i;
};
struct Derived : public Base {
int j;
};
int main() {
std::cout << "Base size = " << sizeof(Base) << '\n';
std::cout << "Derived size = " << sizeof(Derived) << '\n';
}
This tells us that Base and Derived have a different size. But you're trying to put these two objects into the same container because they're related. Round peg and square peg are related... They won't fit into the same hole, and this is the problem we have now.
The vector creates space in memory for your elements based on the type you supply, and then it requires you to pass it exactly that type to populate those spaces with, or a type that has a conversion mechanism to the storage type.
If you want to have a container of different types, you'll need to use pointers, but then you're going to run into the problem that what you get back will be a pointer to the base type and you will need to provide yourself with a way to distinguish different player types.
See Store derived class objects in base class variables for the C++98 approach. In modern C++ (11 and 14) you should use smart pointers, e.g.
std::vector<std::unique_ptr<Base>>
std::vector<std::shared_ptr<Base>>
Presumably default constructing a Midfielder doesn't make a lot of sense, so you can reserve the memory, then emplace_back into the vector.
std::vector<Player> midfielder {};
midfielder.reserve(8);
midfielder.emplace_back("Default ",0,"Midfielder");
midfielder.emplace_back("David Armitage ",1,"Midfielder");
midfielder.emplace_back("Tom Rockliff ",2,"Midfielder");
midfielder.emplace_back("Gary Ablett ",3,"Midfielder");
midfielder.emplace_back("Dyson Heppel ",4,"Midfielder");
midfielder.emplace_back("Scott Pendlebury",5,"Midfielder");
midfielder.emplace_back("Michael Barlow ",6,"Midfielder");
midfielder.emplace_back("Jack Steven ",7,"Midfielder");
midfielder.at(0) = Midfielder("Default ",0,"Midfielder"); is a statement. You've put that and similar statements in (global) namespace scope. That's your bug. Only declarations may be in namespace scope. You must put your statements inside a function.
The error message stems from the fact that declarations which don't start with a keyword start with a type name. Since midfielder is not a keyword, the compiler expects it to be a type name but it isn't one, so you get the error.

Pattern State in C++

I am trying to implement the Pattern State in C++.
I have my client: Player
State as the interface
and the 2 State: In and Out
This is my In.h:
#ifndef ODA_IN_H
#define ODA_IN_H
#include <vector>
#include "Player.h"
#include "Hand.h"
using namespace std;
class In : public State {
public:
In(Player* player);
void doYouChange();
Card throwCard(int i);
void showHand();
void setHand(vector<Card> &other);
private:
Player* player;
Hand hand;
};
#endif
And the In.cpp:
#include <iostream>
#include "In.h"
using namespace std;
In::In(Player* player) {
this->player = player;
cout << player->getName() <<endl;
}
void In::doYouChange() {
string sth;
do {
cout << player->getName() << ", Do you want to leave for this round?(Yes/No)?";
cin >> sth;
} while (sth != "No" && sth != "Yes");
if (sth == "Yes") {
player->setState(player->getOut());
}
}
Card In::throwCard(int i) {
Card c = hand.getCard(i);
return c;
}
void In::showHand() {
hand.showHand();
}
void In::setHand(vector<Card> &other) {
hand.setHand(other);
}
So the constructor can write out the name, while the doYouChange() method no. And later it breaks totally no message just memory junk:/
I call the doYouChange() from an other class like this:
for (int i = 0; i < playersNb; ++i) {
players[i].doYouChange();
}
The first player okay without name, the on the second it breaks.
I have absolutely no idea. I tried to reimplement and everything but nothing helped.
/****************/
UPDATE:
Creating one Player (as a Client of Pattern State in the constructor I initialize also the states):
Player::Player(string n) {
name = n;
out = new Out(this);
in = new In(this);
this -> state = in;
}
And in the same class with the for I add players in the constructor:
players.push_back(Player(name));
This error will very likely occure due to the fact that player becomes invalid (/destroyed).
Consider the following code:
Player* player = new Player();
In inState(player); // will work
inState->doYouChange(); // will work
delete player;
inState->doYouChange(); // wont work
Without more details we cant give you a concrete solution but just general advices:
Make sure that you know who manages your player objects
Check the cases where these objects become destroyed, try to breakpoint them, do your player objects really become destroyed?
Breakpoint the doYouChange() method and check the player object
Consider using smart pointers to overcome an ownership problem: See std::shared_ptr (there are also many other libraries out there which might provide smart pointers better suiting your needs, e.g Poco or Boost)

How do I print out objects in a vector by overloading the << operator?

Ok so I'm confused about all this operator overloading stuff, the syntax is just weird to me and I'm not that great at programming anyway. So looking around on the internet apparently I think the only way for me to print out objects using cout << is to overload it. So I have a vector of objects and normally if I just had a regular vector of ints or strings then I'd just use an iterator and go through each one and then dereference it to print out whats in it, but I don't think that technique is working for the objects :-/ Here is what I have so far...help!
BarOne.h //my header file
#include <string>
#include <vector>
using namespace std;
class BarOne
{
private:
string name;
string type;
string size;
vector<BarOne> bar; //vector of BarOne objects
vector<BarOne>::iterator it; //iterator for bar
public:
BarOne(); //constructor
void addBottle(string, string, string); //adds a new bottle to bar
void revealSpace();
void printInventory();
friend ostream& operator<<(ostream& os, const BarOne& b);
};
and my implementation looks like:
BarOne.cpp //implementation
#include "BarOne.h"
#include <iostream>
#include <string>
using namespace std;
BarOne::BarOne()
{
//adding 4 default bottles
}
void BarOne::addBottle(string bottleName, string bottleType, string bottleSize)
{
name = bottleName;
type = bottleType;
size = bottleSize;
}
void BarOne::printInventory()
{
for (it = bar.begin(); it != bar.end(); ++it)
{
cout << *it << endl;
}
}
ostream& operator<<(ostream& os, const BarOne& b)
{
os << b.name << "\t\t\t" << b.type << "\t\t\t" << b.size;
return os;
}
so how come when i call printInventory in my main it doesn't do anything? Did I do the overloading wrong? Syntax mistakes?
ok this is the main too:
#include "BarOne.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
string Tiqo, Peruvian, Wellington, Smooze;
string vodka;
string rum;
string whiskey;
string small;
string medium;
string large;
//default bottles
vector<BarOne> bar; //vector of BarOne objects
vector<BarOne>::iterator it; //iterator for bar
BarOne Inventory; //BarOne object
Inventory.addBottle(Tiqo, vodka, large);
bar.push_back(Inventory);
Inventory.addBottle(Peruvian, rum, medium);
bar.push_back(Inventory);
Inventory.addBottle(Wellington, vodka, large);
bar.push_back(Inventory);
Inventory.addBottle(Smooze, whiskey, small);
bar.push_back(Inventory);
^^^thats just a piece of it...the rest is just formatting how things are displayed when the program runs and stuff. So ok I'll try and separate the classes like someone suggested tho. AddBottle adds the info for that object in the vector right? it gets the info and then adds it into the variables name, type and size and then its put into the vector "bar". Or no?
You don't show us your main() program. That code, together with your class design which confuses bar contents with the bar is causing the behavior you see.
The operator << is actually OK for outputting data of a bottle. But I'm sure that the BarOne on which it is called has an empty bar vector. Your addBottle() doesn't add anything anywhere (in particular not to the contained bar). Instead it simply sets the properties (data members) of the outer BarOne object.
The origin of that confusion is your class design, where a BarOne apparently is intended to serve both as bottle and as bar (which contains bottles).
I suggest you restart and try with separate Barand Bottleclasses.
BTW: Keeping the iterator you use in local loops as a class member is not a good idea. Sooner or later you will run into reentrancy problems with such approach. Loop iterators should be local variables, preferably scoped to the loop.

How do I point at a vector in another class?

I have a class that holds a vector, which also inherits another class:
class txtExt : public extention
{
private:
string openedFile_;
public:
vector<string> txtVector; //the vector i want to call
};
I fill the vector in a method within a class:
class Manager : public extention
{
// there is some other code here that I know does work
// and it calls this function:
void organizeExtention(string filename, string ext)
{
if(ext == "txt")
{
txtExt txtExt;
txtExt.txtVector.pushback(filename);
}
}
}
and this is my main class where i attempt to call the vector:
int main()
{
// some code here that does previous operations like getting the path
// and filling the vector
// I've tried many ways of trying to call the vector
// here is an example of one:
vector<txtExt*> testVector;
for(int i = 0; i < testVector.size(); ++i)
{
cout << testVector[i] << endl;
}
return 0;
}
I have a few questions:
Am I calling the vector wrong?
Is my vector empty?
Do I have to make my vector global, so other classes can see it?
Note: I've been able to print out the vector where I load the vector using a very simple for loop
Well, as has been said you have a few errors in the code posted, and you maybe have some misunderstandings as well. But to answer the question asked, this
testVector[i]->txtVector
is the way to access the txtVector object that is inside each of your txtExt objects.
If that doesn't work for you then it's because one of the other errors/misunderstandings you have in your code.
To summarize:
reread the first chapters of a good C++ book ( The Definitive C++ Book Guide and List ), then try try to fix your program and deal with each error one at the time.
There are several errors in your code.
First of all, there's no operator << for printing entities of the type txtExt*.
Even object of type txtExt is not printable just like that.
In addition, the testVector you made is empty, so no .size() will be zero, and there's going to be no looping.
Are you really sure that you like to inherit both your classes from 'extension' ?
You can't call a vector, you can access it.
Having a data member (like the vector) public is not a good idea.
Calling a variable by the same name as a class is a very bad idea.
I have trouble guessing what your code should do. Here's a simple example of things you need to understand:
#include <iostream>
#include <vector>
#include <string>
class TxtExt
{
public:
std::vector<std::string> txtVector;
};
int main(){
TxtExt oneTxtExt;
oneTxtExt.txtVector.push_back("hello");
oneTxtExt.txtVector.push_back("world");
for( auto &i : oneTxtExt.txtVector ){
std::cout << i <<std::endl;
}
}
The following code is correct, but has absolutely no effect. You could as well just write {}:
{
TxtExt TxtExt;
TxtExt.txtVector.pushback(filename);
}
You here create a new object, push back to it (btw it is called push_back), but then the object is destroyed at the end of the scope. Also, don't name you objects the same as the class, it becomes really confusing.