Virtual method being called instead of derived method - c++

i'm having trouble with an inherited function and i can't seem to figure out why it's behaving the way it is, and haven't been able to find an answer in other questions on SO.
I'm working on a small game and the inherited function is responsible for the interactions between the player and objects, if the player attempts to move to a space that is already inhabited by one of the various child classes of "Obstacle", it will call the "Bool GetMove" method of that object, which then executes its unique rules and returns a True if the game can place the player on the space, or False if it cant.
This is the base class header and its getmove method:
class Obstacle
{
public:
const char* id;
Obstacle* _properlyinitialized; //a pointer that points to the object itself, required by the teacher who gave the assignment.
string Name;
mutable bool Moveable;
int x;
int y;
Obstacle();
Obstacle(string Name, bool Moveable, int x, int y);
virtual ~Obstacle();
bool properlyInitialized();
friend std::ostream& operator<<(std::ostream& stream, Obstacle& Obstacle);
virtual bool getmove(const char*, std::vector<std::vector<std::vector<Obstacle> > >&);
virtual void leavetile(std::vector<std::vector<std::vector<Obstacle> > >&);
};
bool Obstacle::getmove(const char* direction,std::vector<std::vector<std::vector<Obstacle> > >& _board){
cout << "wrong getmove" << endl; //this method should never be called.
return true;
};
One of the inherited classes and its getmove method:
class Barrel: public Obstacle
{
public:
Barrel():Obstacle(){};
Barrel(string Name, bool Moveable, int x, int y);
~Barrel(){};
bool getmove(const char*, std::vector<std::vector<std::vector<Obstacle> > >&);
void leavetile(std::vector<std::vector<std::vector<Obstacle> > >&);
};
bool Barrel::getmove(const char* direction,std::vector<std::vector<std::vector<Obstacle> > >& _board){
cout << "barrel getmove" << endl;
if(strcmp(direction, "OMHOOG") == 0){ //what direction to move?
if(_board[this->x][this->y-1][0].properlyInitialized()){ //is that object already inhabited by an object?
if(_board[this->x][this->y-1][0].Moveable){ //can the object be moved?
if(_board[this->x][this->y-1][0].getmove(direction, _board){//move the object
_board[this->x][this->y-1][0] = *this; //move the barrel
_board[this->x][this->y-1][0]._properlyinitialized = &_board[this->x][this->y-1][0];
return true; //return true
}
else{
return false; //an object is in the way, the barrel can't be moved
}
}
else{
return false; //an object is in the way, the barrel can't be moved
}
}
else{
_board[this->x][this->y-1][0] = *this; //move the barrel
_board[this->x][this->y-1][0]._properlyinitialized = &_board[this->x][this->y-1][0];
return true; //return true
}
} //This is for direction "up", i left the other directions out because they're almost equal.
The method is called as follows:
//"this" is a board object
if(this->playfield[this->_player->x][(this->_player->y)-1][0].getmove(direction, this->getBoard())){
//do some stuff
}
I have considered changing the Obstacle object to a pure virtual object, but i need dummy "Obstacle" objects elsewhere, so this isn't an option.

The second argument of getmove should be a
std::vector<std::vector<std::vector<Obstacle*>>>&
Note that the inner most vector is of Obstacle* and not Obstacle? This way the correct virtual function will get called, and more importantly, you won't run into object slicing

Related

How do I properly call setters on a return constant referenced class member

My problem is that I am trying to access none constant setter of a constant reference of a class member resulting in the error(C2662). If I make the values being set mutable, and the setter constant, then I am okay, but I have read that you should avoid doing this, but can't find another way to do it.
Definition of vector2D:
class vector2D {
int _x;
int _y;
public:
vector2D() :
_x(0),
_y(0) {};
// Getters
int xGet() { return _x;};
int yGet() { return _y;};
// Setters
void xSet(int x) {
if (x > 100) {
_x = 100;
return;
} else if (x < 0) {
_x = 0;
return;
} else {
_x = x;
return;
}
};
void ySet(int y) {
if (y > 100) {
_y = 100;
return;
} else if (y < 0) {
_y = 0;
return;
} else {
_y = y;
return;
}
};
};
Definition of npc :
class npc {
vector2D _position;
public:
npc () {};
const vector2D& positionGet() const{
return _position;
};
};
main.cpp :
main () {
vector2D myPos;
myPos.xSet(2); //Okay
npc myGuy;
myGuy.positionGet().xSet(2); //C2662
return 0;
}
What I have tried :
I tried to make xSet/ySet constant functions, but that then gives me an error(expresion must be a modifiable lvalue), which makes sense. I have been reading articles about this, but the correct way has never really been clear.
I tried making x/y mutable, and then that would let me make the setter functions constant, which does get rid of the error, but then I read that a lot of people say not to use mutable, which what other way should this be done?
I also tried to make the returned value of '_position' none constant, but isn't that not safe to do???
Note : I am also trying hard to make my questions better, and so please message/leave comment on how I could have asked this better :D
EDIT: What I have found out
So what a lot of people suggest is just to return a none constant reference of '_position', but the problem I have found with this is that you can directly assign values to the returned reference.
vector2D newPos;
myGuy.positionGet() = newPos;
Which is bad because the returned value is a private member, so therefore shouldn't be able to be directly assigned.
It is also bad because if the npc is passed to a function by reference, and then the above is done it calls the destructor on the vector2D once it goes out of scope.
void functTest (npc & ch1) {
vector2D c1;
ch1.positionGet() = c1;
return;
}
which for some reason also destroys ch1._position ???
If you want your getter to return a mutable reference, then do that.
You want to call positionGet() and get an object that you can modify.
So don't make it const!
vector2D& positionGet() {
return _position;
};
Simple as.
You could provide both mutable and constant interface for the position:
class npc {
vector2D _position;
public:
npc () {};
const vector2D& position() const { return _position; };
vector2D& mutable_position() { return _position; };
};
Yes, when you call mutable_position() a reference to the private member will be returned, but if that is the intention of the programmer (as indicated by the explicit use of "mutable_" in the call), then it should be okay.

Setting x or y of a POINT2f/VECTOR2f variable in a class using a member function

I have the following classes:
//----------------------------------------------------------------------
// CHARACTER CLASS
//----------------------------------------------------------------------
class Character
{
private:
POINT2f char_position;
public:
VECTOR2f char_velocity;
Character();
~Character();
// Mutators
void SetChar_Position(POINT2f p);
void SetChar_Velocity(VECTOR2f v);
// Accessors
POINT2f GetChar_Position();
VECTOR2f GetChar_Velocity();
};
//----------------------------------------------------------------------
// PLAYER CLASS - INHERITED FROM "CHARACTER" CLASS
//----------------------------------------------------------------------
class Player : public Character
{
private:
public:
int health;
Player();
~Player();
void SetPlayer_Health(int h);
int GetPlayer_Health();
};
So essentially the player class inherits from the character class.
The Character class has member function which lets you set the characters position and velocity, which take in a POINT2f and VECTOR2f.
Within my main bit of code I create a player character Player Player1 and than set the balls velocity and position if a button is pressed:
if (ui.isActive('A')) // Check to see if "A" key is pressed
{
// Player Ball
Player1.SetChar_Velocity.x = -12.0;
Player1.SetChar_Position.x += (Player1.GetChar_Velocity.x*dt);
Player1.SetChar_Velocity.x += (acceleration*dt);
}
I'm currently getting errors that say left of .x must have class/struct/union, so I change Player1.SetChar_Velocity.x = -12.0; to Player1.SetChar_Velocity().x = -12.0; which than brings up the error expression must have class type and to few arguments in function call.
Does anyone know of a method that will allow my to only manipulate the x number of the char_velocity only. also I understand that my code to Set the .x velocity isn't correct because I'm not passing in a VECTOR2f value.
In order to achieve what you want to do, you will want the return type of you Get_ methods to be a reference (wiki). Your code will then look like
class Character
{
private:
POINT2f char_position;
public:
VECTOR2f char_velocity;
// Accessors
POINT2f& GetChar_Position() { return char_position; }
VECTOR2f& GetChar_Velocity() { return char_velocity; }
};
Also, it is often advised or required to be able to preserve const-correctness in your code, so you might want to add
const POINT2f& GetChar_Position() const { return char_position; }
const VECTOR2f& GetChar_Velocity() const { return char_velocity; }
This will allow you to do some calls like
POINT2f current_pos = a_char.GetChar_Position(); // const
a_char.GetChar_Velocity().x += 2; // non-const
Please note that it is often advised to pass the structures as const references instead of copies (although this might not hold true depending on your c++ version and your types, you can see this question for clarification), hence change your
void SetChar_Position(POINT2f pos) { char_position = pos; }
void SetChar_Velocity(VECTOR2f vel) { char_velocity = vel; }
to
void SetChar_Position(const POINT2f& pos) { char_position = pos; }
void SetChar_Velocity(const VECTOR2f& vel) { char_velocity = vel; }

Virtual function issue in C++ [duplicate]

This question already has answers here:
Why is virtual function not being called?
(6 answers)
Closed 9 years ago.
AoA,
I am making a console game of chess, But I am stuck at polymorphism, below is the classes and functions definitions
/* old Part
//Base Class
class Piece /*Parent class */
{
protected:
Position* pCoord;
std::string color;
char symbol;
public:
Piece(Position* Coord,std::string Color,char symbol);
Position GetCurrentPos();
std::string GetColor();
void SetColor(std::string color);
void Draw();
virtual bool SetPos(Position* newPos){MessageBox(NULL,L"Virtual Running",L"Error",MB_OK); return true;};
virtual ~Piece();
};
/* Inherited classes */
//Child classes
class Pawn: public Piece
{
private:
std::vector<Position>* allowPos;
public:
Pawn(Position* Coord,std::string Color,char symbol);
~Pawn();
std::vector<Position>* GetThreatendFields();
bool isValidMove(Position* newPos);
bool SetPos(Position* newPos);
};
//Child classes
class Bishops: public Piece
{
private:
std::vector<Position>* allowPos;
public:
Bishops(Position* Coord,std::string Color,char symbol);
~Bishops();
std::vector<Position>* GetThreatendFields();
bool isValidMove(Position* newPos);
bool SetPos(Position* newPos);
};
//Here is the implementation of child class function SetPos
bool Pawn::SetPos(Position* newPos)
{
bool isSet = false;
this->pCoord = new Position();
this->pCoord = newPos;
isSet = true;
MessageBox(NULL,L"Child function running",L"Yuhuu!",MB_OK);
return isSet;
}
class ChessBoard
{
private:
Position ptr; //dummy
int SelectedPiece;
vector<Piece> pPieceSet;
bool isSelected;
public:
ChessBoard();
~ChessBoard();
void ShowPieces(Player *p1,Player *p2);
void Draw();
void MouseActivity();
void Place(Piece& p);
};
//it just shows the peices acquired from player objects..dummy vector pointer
void ChessBoard::ShowPieces(Player* p1,Player* p2)
{
std::vector<Piece>* vPiece = p1->GetPieces();
for( int i=0;i<vPiece->size();i++ )
{
Piece& piece = vPiece->at(i);
Place(piece);
piece.Draw();
}
vPiece = p2->GetPieces();
for( int i=0;i<vPiece->size();i++ )
{
Piece& piece = vPiece->at(i);
Place(piece);
piece.Draw();
}
}
*/
/*new part
I did what you say
Player::std::vector<Piece*> *vPieceSet;
Player::Player(int turn)
{
this->turn = turn%2;
this->vPieceSet = new std::vector<Piece*>;
}
void Player::Initialize() //Initial and final ranges for position
{
//Initialization of pieces to their respective position
Position pos;
Piece *pPiece;
if( this->turn == 0 )
{
this->SetName("Player 1");
for( int i=8;i<16;i++ )
{
pos.SetPosition(i);
Pawn pPawn(&pos,"blue",'P');
pPiece = &pPawn;
this->vPieceSet->push_back(pPiece);
}
//other classes same as above
}
It runs fine at initialzation function(stores all classes fine) but when use function to get the vector object
std::vector<Piece*>* Player::GetPieces()
{
std::vector<Piece*>* tPieces = this->vPieceSet;
return tPieces;
}
//In main.cpp
it doesnot return the vector object
Player p1(0),p2(1);
p1.Initialize();
p2.Initialize(); //initialization done perfectly while debugging
vector<Piece*> *obj = p1.GetPieces(); //returns garbage
Piece* pObj = obj->at(0); //garbage
cout<<pObj->GetColor(); // garbage
*/new part
Sounds like I have another problem!
When you use polymorphism, what you are really trying to do is instantiate an object of derived type and call the methods on that object through a pointer or reference to the base object.
class Foo
{
public:
virtual void DoIt () { cout << "Foo"; }
};
class Bar
:
public Foo
{
public:
void DoIt () { cout << "Bar"; }
};
int main()
{
Foo* foo = new Bar;
foo->DoIt(); // OUTPUT = "Bar"
Foo& fooRef = *foo;
fooRef.DoIt(); // OUTPUT = "Bar"
}
In order for this to work, you need to use either a pointer or a reference to the object. You can't make a copy of the object using a the base class. If you make a copy, you will slice the object.
int main()
{
Foo* foo = new Bar;
foo->DoIt(); // OK, output = "Bar"
Foo fooCopy = *foo; // OOPS! sliced Bar
fooCopy.DoIt(); // WRONG -- output = "Foo"
}
In your code, the Piece class is intended to be polymorphic, and in your ChessBoard class you have a vector of this class:
class ChessBoard
{
private:
vector<Piece> pPieceSet;
};
Since this is a vector of the Piece object itself, and not a pointer-to-Piece, anything you put in here will be sliced. You need to change pPieceSet to be a vector of pointers-to-Piece:
vector <Piece*> pPieceSet;
You have further problems in Initialize, which need to be refactored anyway. For one thing, you have another vector of Piece objects, and there are two problems here. First, it needs to be a vector of pointers, and second, why do you need another vector at all when there is already one associated with the ChessBoard? I didn't thouroughly examine your code so maybe you do need it, but this seems like an error. There should probably just be one collection of pieces, in the ChessBoard.
In your Initialize method:
Piece *pPiece;
// ...
Pawn pPawn(&pos,"blue",'P');
pPiece = &pPawn;
vPieceSet.push_back(*pPiece);
There are a couple of problems. One, you are pushing back a sliced copy of the Piece, which will be fixed when you change your vector to store pointers. Second, if you just change this like so:
Piece *pPiece;
// ...
Pawn pPawn(&pos,"blue",'P');
pPiece = &pPawn;
vPieceSet.push_back(pPiece); // <-- not dereferencing
You will have a new problem because you'll be storing the pointer to a local (automatic) variable. Best is to do this:
Piece* pPiece = new Pawn (...);
// ...
vPieceSet.push_back (pPiece);
Please don't forget to delete everything you new. This is best handled by using smart pointers rather than raw pointers. In C++03 we have auto_ptr, but those can't go in a vector. Instead you'll need to use Boost or something else, or just store raw pointers. In C++11, we now have unique_ptr (preferred) and shared_ptr, which can go in to a vector.
In C++11, the best solution here is to have a vector declared as:
vector <unique_ptr <Piece> > pPieceSet;
...unless you have some compelling need to use shared_ptr instead.
As others have mentioned, it is a slicing issue, and the issue is created here:
class Player
{
private:
std::string pName;
std::vector<Piece> vPieceSet; // <-- This is your problem
int turn;
public:
Player(int turn);
~Player();
void Initialize();
std::string GetName();
void SetName(std::string Name);
int GetTurn();
std::vector<Piece>* GetPieces();
};
You are storing them in the vector as instances of Piece, which is slicing off the details of the piece (e.g. the Bishop implementation). You should modify it to something like:
class Player
{
private:
std::string pName;
std::vector<Piece*> vPieceSet; // or better, use a smart pointer wrapper
int turn;
public:
Player(int turn);
~Player();
void Initialize();
std::string GetName();
void SetName(std::string Name);
int GetTurn();
std::vector<Piece*> GetPieces(); // note this change as well
};
With your additional question/edit, you are getting another unrelated problem:
void Player::Initialize() //Initial and final ranges for position
{
Position pos; // position is declared inside the scope of Initialize
Piece *pPiece;
if( this->turn == 0 )
{
this->SetName("Player 1");
for( int i=8;i<16;i++ )
{
pos.SetPosition(i);
Pawn pPawn(&pos,"blue",'P'); // you are passing the address of position to the Pawn, and Pawn is within the scope of this loop
pPiece = &pPawn; // you are storing the address of the Pawn
this->vPieceSet->push_back(pPiece);
}
// Pawn is now out of scope and pPiece points to the memory location Pawn *used* to be at (but will likely be overwritten soon).
// As soon as this function returns, you have the same problem with pos
}
You need to allocate those variables on the heap (hence the reason we suggested smart pointer wrappers).

Virtual function implementation C++ not working

I'm new to C++, and I'm trying to write a simple code to compare two objects of subclasses of a parent class called Comparable. I want each subclass to have its own implementation of a method to compare objects based on the data they hold, so I used the virtual keyword:
class Comparable {
public:
virtual int compare(Comparable *other);
};
For example, my subclass HighScoreElement would have its own implementation of compare that would compare the score of the object to the score of another HighScoreElement.
Here is my subclass HighScoreElement:
class HighScoreElement: public Comparable {
public:
virtual int compare(Comparable *other);
HighScoreElement(string user_name, int user_score); // A constructor
private:
int score;
string name;
};
But in my compare implementation in HighScoreElement, I first try to check if the current object's data is the same as other's data. But since the pointer to other is of class Comparable and not HighScoreElement, I can't reference other->score at all in my code, even though HighScoreElement is a subclass of Comparable.
Here is the full code so far:
#include <iostream>
using namespace std;
class Comparable {
public:
virtual int compare(Comparable *other);
};
class HighScoreElement: public Comparable {
public:
virtual int compare(Comparable *other);
HighScoreElement(int user_score, string user_name);
private:
string name;
int score;
};
HighScoreElement::HighScoreElement(int user_score, string user_name) {
name = user_name;
score = user_score;
}
int HighScoreElement::compare(Comparable *other) {
if (this->score == other->score) { // Compiler error right here, other->score is invalid.
// Code to do the comparing if two scores are equal...
}
}
I get a compiler error immediately when I write this code:
if (this->score == other->score)
because other doesn't have data called score, but its subclass, HighScoreElement, does. How can I fix my function implementation so that I can reference the data of "other?" I know my question may sound vague, but any help would be appreciated!
You could implement a virtual function GetScore(), possibly pure virtual in the base class, and use that instead of accessing the field score in your compare function. Make it a const method. On the other hand, Compare could be a method implemented in the base class, that uses this->GetScore() and other->GetScore()
Code stub:
class A {
virtual int getScore() const = 0;
inline bool compare(const A* in) {return (in && this->getScore() == in->getScore());}
//return false also if "in" is set to NULL
}
class B : public A {
int score;
inline int getScore() const {return score;}
}
You can cast the pointer passed to HighScoreElement::compare using "dynamic_cast" (it throws a bad_cast exception on failure).
int HighScoreElement::compare(Comparable *other) {
HighScoreElement *h = NULL;
try
{
ptr = dynamic_cast<HighScoreElement *>(other);
}
catch(std::bad_cast const &)
{
// Handle the bad cast...
}
if (this->score == ptr->score) {
// Code to do the comparing if two scores are equal...
}
}
If you are prepared to accept null pointers, you can use dynamic casts. You can have an overload for the case when you are comparing a HighScoreElement pointer to avoid an unnecessary cast.
#include <iostream>
using namespace std;
class Comparable {
public:
virtual int compare(Comparable *other) = 0; // made pure virtual to compile without definition
};
class HighScoreElement: public Comparable {
public:
virtual int compare(Comparable *other);
int compare(HighScoreElement *other); // comparing to a HighScoreElement ptr, no need to dynamic cast
HighScoreElement(int user_score, string user_name);
private:
string name;
int score;
};
HighScoreElement::HighScoreElement(int user_score, string user_name) {
name = user_name;
score = user_score;
}
int HighScoreElement::compare(Comparable *other) {
HighScoreElement * pHSE = dynamic_cast<HighScoreElement*>(other);
if (pHSE) {
return compare(pHSE);
} else {
return -1; // or however you want to handle compare to non HighScoreElement
}
}
int HighScoreElement::compare(HighScoreElement *other) {
if (this->score == other->score) {
;
}
}
Are you sure it's not
compare( Comparable other )
If (this->score == other.score)

Print out the values stored in vars of different classes, that have the same ancestor

I have this class:
class CComputer {
public:
// constructor
CComputer(string name) {
this->name = name;
};
// overloaded operator << for printing
friend ostream& operator<<(ostream& os, const CComputer& c);
// adds some component for this computer
CComputer & AddComponent(Component const & component) {
this->listOfComponents.push_back(component);
return *this;
};
// sets address for this computer
CComputer & AddAddress(const string & address) {
this->address = address;
return *this;
};
string name;
string address;
list<Component> listOfComponents;
};
and then these classes:
// ancestor for other classes...It's really dummy yet, but I dunno what to add there
class Component {
public:
Component() {};
~Component() {};
};
class CCPU : public Component {
public:
CCPU(int cores, int freq) {
this->cores = cores;
this->freq = freq;
};
int cores;
int freq;
};
class CMemory : public Component {
public:
CMemory(int mem) {
this->mem = mem;
};
int mem;
};
Now I feed my CComputer class with some values:
CComputer c("test.com");
c . AddAddress("123.45.678.910") .
AddComponent(CCPU(8, 2400)) .
AddComponent(CCPU(8, 1200)).
AddComponent(CMemory(2000)).
AddComponent(CMemory(2000)));
And now I would like to print it out with all the info I've put in there (CCPU & CMemory details including)
but how to implement it, to be able to iterate through CComputer::listOfComponents and don't care if I acctually access CCPU or CMemory ? I can add it to that list, but I have really no idea, how to make it, to be able to access the variables of those components.
So the output should look like:
##### STARTING #####
CComputer:
name:test.com
address:123.45.678.910
CCPU:
cores:8,freq:2400
CCPU:
cores:8, freq:1200
CMemory:
mem:2000
CMemory:
mem:2000
###### FINISHED! #####
As others have mentioned, you need to implement a virtual function (e.g. virtual std::string ToString() const = 0;) in the base class that is inherited and overridden by each child class.
However, that isn’t enough. Your code exhibits slicing which happens when you copy your child class instances into the list: the list contains objects of type Component, not of the relevant child class.
What you need to do is store polymorphic instances. Values themselves are never polymorphic, you need to use (smart) pointers or references for this. References are out, however, since you cannot store them in a standard container (such as std::list). Using raw pointers is considered bad style nowadays, but judging from the naming conventions of your classes you don’t learn modern C++ in your class (sorry!).
Therefore, raw pointers is probably the way to go. Change your code accordingly:
Store a list of pointers:
list<Component*> listOfComponents;
Make the argument type of AddComponent a pointer instead of const&.
Call the function by passing a newed object, e.g.:
AddComponent(new CCPU(8, 2400))
Now your code leaks memory left, right and center. You need to implement a destructor to free the memory:
~CComputer() {
typedef std::list<Component*>::iterator iter_t;
for (iter_t i = listOfComponents.begin(); i != listOfComponents.end(); ++i)
delete *i;
}
But now your code violates the Rule of Three (read this article! It’s important, and it may be the most useful thing about C++ you’re going to learn in this programming class) and consequently you also need to implement the copy constructor and copy assignment operator. However, we can’t. Sorry. In order to implement copying for your class, you would have to implement another virtual function in your Component class, namely one that clones an object (virtual Component* Clone() const = 0;). Only then can we proceed.
Here’s a sample implementation in CCPU:
Component* Clone() const {
return new CCPU(cores, freq);
}
… this needs to be done in all classes deriving from Component, otherwise we cannot correctly copy an object of a type that derives from Component and is hidden behind a pointer.
And now we can implement copying in the CComputer class:
CComputer(CComputer const& other)
: name(name)
, address(addess) {
typedef std::list<Component*>::iterator iter_t;
for (iter_t i = other.listOfComponents.begin(); i != other.listOfComponents.end(); ++i)
listOfComponents.push_back((*i)->Clone());
}
CComputer& operator =(CComputer const& other) {
if (this == &other)
return *this;
name = other.name;
address = other.address;
listOfComponents.clear();
for (iter_t i = other.listOfComponents.begin(); i != other.listOfComponents.end(); ++i)
listOfComponents.push_back((*i)->Clone());
return *this;
}
This code is brittle, not thread-safe and error-prone and no competent C++ programmer would ever write this1. Real code would for instance use smart pointers instead – but as mentioned before I’m pretty sure that this would be beyond the scope of the class.
1 What does this make me now, I wonder?
Just add a virtual method to Class Component called e.g. toString(), which returns a string describing the component. Then you can iterate through all components and call toString() without worrying about exactly what each component is. If you do that, then for each computer you would be able to print out the values of all the components.
However, as pointed out in one of the comments, the example output you give in the question outputs the CCPU for all computers, then all the memory for all computers. To order the output like that, you'll need to add another virtual method to Component called e.g. getType() which returns an enum or integer that represents the type of the information. You can then have two for-next loops, one nested inside the other, where the outer loop iterates through all the types and the inner loop iterating through all the computers calling the toString() on all components which match the type specified in the outer for loop.
Here's something that implements this idea.
#include <iostream>
#include <string>
#include <list>
using namespace std;
int const TYPE_CCPU = 1;
int const TYPE_MEMORY = 2;
class Component {
public:
virtual int GetType() { return -1; }
virtual std::string ToString() const {
return "OOPS! Default `ToString` called";
}
};
class CComputer {
public:
typedef std::list<Component*>::iterator iter_t;
// constructor
CComputer(string name) {
this->name = name;
};
~CComputer() {
for (iter_t i = listOfComponents.begin(); i != listOfComponents.end(); ++i) {
delete *i;
}
}
// overloaded operator << for printing
friend ostream& operator<<(ostream& os, const CComputer& c);
// adds some component for this computer
CComputer & AddComponent(Component *component) {
this->listOfComponents.push_back(component);
return *this;
};
// sets address for this computer
CComputer & AddAddress(const string & address) {
this->address = address;
return *this;
};
void PrintType(int type) {
for (iter_t i = listOfComponents.begin(); i != listOfComponents.end(); ++i) {
if ((*i)->GetType() == type)
std::cout << (*i)->ToString() << '\n';
}
}
string name;
string address;
list<Component*> listOfComponents;
};
class CCPU : public Component {
public:
CCPU(int cores, int freq) {
this->cores = cores;
this->freq = freq;
};
int GetType() { return TYPE_CCPU; }
std::string ToString() const {
return "CCPU::ToString()";
}
int cores;
int freq;
};
class CMemory : public Component {
public:
CMemory(int mem) { this->mem = mem; };
int GetType() { return TYPE_MEMORY; }
std::string ToString() const {
return "CMemory::ToString()";
}
int mem;
};
typedef std::list<CComputer*>::iterator iter_c;
int main() {
list<CComputer*> computerlist;
CComputer *c1 = new CComputer("test.com"), *c2 = new CComputer("test2.com");
c1->AddAddress("123.45.678.910").
AddComponent(new CCPU(8, 1200)).
AddComponent(new CMemory(2000));
computerlist.push_back(c1);
c2->AddAddress("987.65.432.10").
AddComponent(new CCPU(8, 2400)).
AddComponent(new CMemory(4000));
computerlist.push_back(c2);
for(int t=TYPE_CCPU; t<=TYPE_MEMORY; t++)
for (iter_c i = computerlist.begin(); i != computerlist.end(); ++i) {
(*i)->PrintType(t);
}
for (iter_c i = computerlist.begin(); i != computerlist.end(); ++i) {
delete (*i);
}
}
Implement ToString() in each of your classes. In .NET this is a standard even the "object" type implements.