How can i link the vector elements to a pointer - c++

I need help in the class design workflow with the following functionality.
I have a class with the name of Stage the stage has a variable of class Director as vector and i would want to point to these data elements of the vector from another class Channel.
class Stage
{
private:
int time;
std::vector<Director> directors;
public:
Stage()
{ }
void AddDirector(Director director)
{
directors.push_back(director);
}
Director* GetDirector(int index)
{
return &directors[index];
}
void DeleteDirector(std::string dirName)
{
// remove the director from the vector which matches the name of the input string
}
};
////////////////////////////////////////////////////////////////////////////////////////////////
class Director
{
private:
int time;
std::string stdstrDirName;
public:
Director()
{ }
std::string GetName()
{
return stdstrDirName;
}
void SetName(std::string name)
{
stdstrDirName = name;
}
// GetTime and SetTime
};
class Channel
{
private:
int time;
std::string stdstrChannelName;
Director* dir;
public:
Channel()
{ }
std::string GetName()
{
return stdstrChannelName;
}
void SetName(std::string name)
{
stdstrChannelName = name;
}
std::string GetDirectorName()
{
dir->GetName();
}
void SetDirector(Director* director)
{
dir = director;
}
};
This is how i would point them.
int main()
{
Stage stage; // Create Stage Object
Director d1, d2, d3; // Create Director Objects
Channel channel;
d1.SetName("D1"); d2.SetName("D2"); d3.SetName("D3");
stage.AddDirector(d1); stage.AddDirector(d2); stage.AddDirector(d3);
channel.SetDirector(stage.GetDirector(1)); // Link Director to Channel
}
This approach has a drawback whenever the vector gets resize the pointers in the Channel will not hold reference to their valid object.
I need help in what should be the design of the class structure ?

Perhaps your vector could store pointers to the Director objects rather than the objects themselves. That way, resizes will not affect existing pointers.

Have you thought of using reference(&) instead of pointers?

Related

How to design c++ class in a way to have a base attributes and add attributes for few cases

I have a basic class ContactDetails which has a private variables as string name and string address. This ContactDetails data structure is used in my program for all entities. For some entities, I need other info on top of name and address, such as phone number, pin code etc. How to design the class.
class ContactDetails {
private:
std::string name;
std::string address;
public:
ContactDetails() {
this->name = "";
this->address = "";
}
std::string getName() { return name; }
std::string getAddress() { return address; }
void setName(std::string n) { name = n; }
void setAddress(std::string n) { address = n; }
}
class ContactDetailsHelper {
public:
ContactDetails getX() {
ContactDetails obj;
obj.setName("X");
obj.setAddress("New York");
return obj;
}
ContactDetails getY() {
//Y has phone number, pin code, county code etc details available.
ContactDetails obj;
obj.setName("Y");
obj.setAddress("Chicago");
//need to set more details in the object
return obj;
}
If we take phone number, pin code, county code as a private member in ContactDetails class, most of the time it would be empty. So how to design the class in such a way like extra details we could put it in another class and if needed for any entity we could use them.

Creating Vector elements without calling a constructor

Lets say I have two classes car and service. Is it possible to create the elements for both vector objects(note: I don't know if is actually refereed to as vector objects), of the car and service classes. Once both elements are created I would only like the car class constructor to be called later to have the service constructor called to get the user information?
Also if it is possible is it possible without having to change the Service constructor to a method?
using namespace std; // I know this is not the best, prof wants us to use it
class Car { Car() { //Get data from user } };
class Service { Service(){ //Get data from user } };
int main () {
int num;
vector<Car> car;
vector<Service> service;
car.push_back(Car{});
service.push_back();
for (int i = 0; i < car.size(); i++)
car[i].display(i);
cout << endl << car.size() + 1 << ". exit";
cin >> num;
service[num].Service::Service();
}
I would recommend using a std::map instead of std::vector which choice naturally follows from your task. By using it, you will be storing valid Service elements only.
map<int,Service> service;
car.push_back(Car{});
for (int i = 0; i < car.size(); i++)
car[i].display(i);
cout << endl << car.size() + 1 << ". exit";
cin >> num;
service[num]; //Service constructor will be called
I'm thinking you are looking for something like this:
class Car {
private:
std::string _make;
std::string _model;
std::string _vinNumber;
std::size_t _year;
public:
Car() : _year( 0 ) {} // default
Car( const std::string& make, const std::string& model,
const std::string& vinNumber, const std::size_t& year ) :
_make( make ), _model( model ),
_vinNumber( vinNumber ), _year( year ) {
}
void setCarInfo( const std::string& make, const std::string& model,
const std::string& vinNumber, const std::size_t& year ) {
_make = make;
_model = model;
_vinNumber = vinNumber;
_year = year;
}
std::string makeOf() const { return _make; }
std::string modelOf() const { return _model; }
std::string vinNumberOf() const { return _vinNumber; }
std::size_t yearOf() const { return _year; }
};
class Service {
private:
std::string _dealership;
std::size_t _currentMiles;
public:
Serivce() {}
std::string dealershipOf() const { return _dealership; }
std:size_t currentMilesOf() const { return _currentMiles; }
void setOrChangeDealership( const std::string& dealership ) {
_dealership = dealership;
}
void setOrChangeCurrentMiles( std::size_t miles ) {
_currentMiles = miles;
}
void setOrChangeCurrentMiles( const std::size_t& miles ) {
_currentMiles = miles;
}
};
int main() {
std::vector<Car> cars;
std::vector<Service> services;
// you can add Car to vector by either default constructor
// to be filled out later or by user defined constructor
cars.push_back( Car( "Honda", "Civic", "75273250323XMD252AG9", 2017 ) );
// or
cars.push_back( Car() );
// then you can at some point in time update elements in container
cars[i].setCarInfo( "Dodge", "Charger", "9259356M325D2680A217B", 2015 );
// As with the service class there is only a "default" constructor
services.push_back( Service() );
// Service's members will have to be updated manually and later.
return 0;
}
Regardless of what container you use, or even if you have a single instance of a class object; a CTOR for that class will be called. The only way that one will not is if either A: you declare it as protected or private in the class the prevents the class from being declared which is used with inheritance and polymorphism, or if you declare the constructor as a deleted function: SomeClass() = delete. There is no possible way to have a class instance without its constructor being called either implicitly by the compiler or explicitly by you.
Even something as simple as this:
class A {
public:
int x;
};
int main() {
A a;
a.x = 5;
return 0;
}
The line A a; behind the scenes the compiler will invoke A() on a so it would actually look like this:
A a();
Using its default constructor.
Since C++11, you have the list-initialization for vector and other containers.
http://en.cppreference.com/w/cpp/language/list_initialization
Which means, you can put an enumeration of elements in a vector while initialization.
You can use your own class constructor in it:
std::vector<Car> cars {Car(...), Car(...), Car(...)}; //C++11
Since I can't comment your question yet, is it what you expected?

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).

a function instead of copy-and-paste programming

I have an object, every member variable in this object has a name which I can acquire it by calling get_name() ,what I want to do is concatenate all the names of the member variables in alphabetical order, then do something. for example:
class CXMLWrapper<class T>
{
public:
CXMLWrapper(const char* p_name) : m_local_name(p_name)
{
}
//skip the get_name(), set_name() and others
private:
string m_local_name;
T m_type_var;
}
class object
{
public:
object() : m_team("team"), m_base("base")
{
}
public:
CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;
...
}
I have to hard-code like this:
object o;
string sign = o.m_base.get_name();
sign += o.m_team.get_name();
I need a function to do this instead of copying and pasting when the object varies. Anyone has an idea?
One way to do this in normal C++, provided all of the members belong to the same class or are derived from some base class will be to use variable number of arguments to a function. An example follows.
#include <stdarg.h>
string concatenateNames(int numMembers, ...)
{
string output;
va_list args;
va_start(args, numMembers);
for(int i = 0; i < numMembers; i++)
{
MemberClass *pMember = va_arg(args, MemberClass*);
output += pMember->get_name();
}
va_end(args);
return output;
}
class Object
{
public:
MemberClass x;
MemberClass y;
MemberClass z;
};
int main()
{
Object o;
string sign = concatenateNames(3, &o.x, &o.y, &o.z);
}
If the types of all the members are different, you can look into variadic templates of C++11x: http://en.wikipedia.org/wiki/Variadic_Templates, but I can't seem to find a way to do otherwise.
If variables which have name have a same type (or these types belongs one hierarchy) you can use map of these vars. Is not good way, but maybe it helps you
Example
class object
{
public:
object() //: m_team("team"), m_base("base")
{
this->vars["m_team"] = CXMLWrapper<string>("team");
//.....
}
public:
map<string, CXMLWrapper<string> > vars;
/*CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;*/
...
}
object o;
string sign;
for(auto& x : o.vars)//i cannot remember syntax of for of map
sign += x.get_name;
PS Sorry for my writing mistakes. English in not my native language.
One method is to have an external library of member names which the CXMLWrapper class updates:-
class BaseXMLWrapper
{
public:
void ListMembers (const char *parent)
{
// find "parent" in m_types
// if found, output members of vector
// else output "type not found"
}
protected:
void RegisterInstance (const char *parent, const char *member)
{
// find 'parent' in m_types
// if not found, create a new vector and add it to m_types
// find 'member' in parent vector
// if not found, add it
}
private:
static std::map <const std::string, std::vector <const std::string> >
m_types;
};
class CXMLWrapper <class T, const char *parent> : BaseXMLWrapper
{
public:
CXMLWrapper(const char* p_name) : m_local_name(p_name)
{
RegisterInstance (parent, p_name);
}
// you could override assignments, copy and move constructors to not call RegisterInstance
//skip the get_name() set_name()
private:
m_local_name;
}
class object
{
public:
object() : m_team("team"), m_base("base")
{
}
public:
CXMLWrapper<string, "object"> m_team;
CXMLWrapper<string, "object"> m_base;
...
};
This does add overhead to the construction of objects, but as it's only a constructor overhead it might not affect overall system performance much.
This looks like a "observe pattern", you just need to keep a single copy in object as a member variable "string name_;", and pass the name_s's reference into CXMLWrapper like this:
class CXMLWrapper<class T>
{
public:
CXMLWrapper(const string &name)
: local_name_(name)
{
}
//skip the get_name() set_name()
private:
const string &local_name_;
}
class object
{
public:
object()
: team_("team"),
base_("base"),
m_team(team_)
, m_base(base_)
{
}
public:
string team_;
string base_;
CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;
}

How can I create multiple items with one class in C++?

I have the class Furniture with:
Furniture.h:
#include <iostream>
#include <string>
using namespace std;
class Furniture {
public:
Furniture();
~Furniture();
void setname(string name);
void setprice(double price);
double getprice();
string getname();
virtual void printSpecs();
private:
string name;
double price;
protected:
static int NumberOfItems;
int Id;
};
furniture.cpp:
#include "furniture.h"
Furniture::Furniture() {
}
Furniture::~Furniture() {
}
void Furniture::setname(string name) {
this->name = name;
}
string Furniture::getname()
{
return this->name;
}
void Furniture::setprice(double price) {
this->price = price;
}
double Furniture::getprice() {
return this->price;
}
void Furniture::printSpecs() {
cout<<"Price: "<<this->price<<endl;
cout<<"Name: "<<this->name<<endl;
}
int main() {
Furniture *model = new Furniture();
model->setname("FinalDestiny");
model->setprice(149.99);
model->printSpecs();
delete model;
}
Everything works fine but I want to add multiple furniture items with the same class and just update the NumberOfItems. Is there any way to do that?
Also, is my code ok? I mean, how can I improve it? I'm quite new to OOP and I'd like to learn some good practices.
Thanks.
The idea is conceptually broken. You cannot do that; you really need different objects.
Alternatively, if you really want to have multiple identical items, you can create one item and create multiple pointers to it, and maintain a separate count for the number of active items. A shared_ptr does that for instance.
That said, your code shouldn’t use pointers at all, this is a common anti-pattern in C++ code. Furthermore, your code probably shouldn’t have setters, provide a proper constructor instead:
int main() {
Furniture model("FinalDestiny", 149.99);
model.printSpecs();
}
Much shorter, simpler, and no possiblity of leaking memory.
To keep track of the number of items, you can update the number of items in the constructor:
Furniture::Furniture() {
Id = NumberOfItems++;
}
and decrement in the destructor if you want:
Furniture::~Furniture() {
NumberOfItems--;
}
To access the item by Id, you need to have an extra manager class or use a map:
std::map<int,Furniture*> items;
which you can pass as parameter to the constructor and update it there:
Furniture::Furniture(std::map& items) {
Id = NumberOfItems++;
items[Id] = this;
}
And, outside, you can simply retrieve items with:
Furniture* f = items[3];
I would write in this way
#include <iostream>
#include <string>
using namespace std;
class Furniture {
public:
Furniture(string name = "", double price = 0)
: name(name), price(price), Id(NumberOfItems++)
{}
Furniture(const Furniture &f)
: name(f.getname()), price(f.getprice()), Id(NumberOfItems++)
{}
void setname(string name) { this->name = name; }
void setprice(double price) { this->price = price; }
double getprice() const { return price; }
string getname() const { return name; }
virtual void printSpecs() {}
private:
string name;
double price;
protected:
static int NumberOfItems;
int Id;
};
int Furniture::NumberOfItems;
int main_furniture(int, char **)
{
Furniture a("product 1", 100);
Furniture x(a), y(a), z(a);
}
I've inlined just to simplify. What's interesting to you should be the copy constructor implementation, and (OT) you forget the const on getter...
Just increment NumberOfItems in the constructor, and decrement it in the destructor.
Store the furniture instances in an array or better in a vector. You can access them with an index or iterator. The NumberOfItems field doesn't belong in the furniture class, an instance of furniture shouldn't know about how many furniture items there are in the system. Use the size () method from vector to get the furniture item count.