C++ Class with member varialble vector <another class> - c++

I have an assignment to make Information system about resorts in a country, be able to read/write data for the resorts from/to file and modifying it.
class CTоurist{
string m_StrName;
string m_StrCountry;
int m_iAge;
public:
//constructors, mutators, accessors overloading operator <<,>>
};
I don't have problem writing this class. And here I have class which contains as member variable vector of the first class's objects
class CHotel
{
string m_strHotelName;
int m_iNumberOfBets;
double m_dAveragePrice; //average price per bet in the hotel
vector <CTourist> m_vecTourists; //vector of tourists rested in the hotel
public:
.....
};
And one more class Resort containing as member variable vector of the second class's objects
class CResort
{
string m_ResortName;
unsigned m_Height;
vector<CHotel*> m_Hotels;
public:
.....
};
So here is the problem. I'm not sure how to write the accessor,mutator and constructors for that vector variable so I can use them property. Thank you for checking and if someone could help me figure out these functions I'll be really grateful!

if i understand correctly you want to know the best way to get your hotels from cResort.
i would recommend
cHotel* GetHotelByName(std::string& a_sName)
{
for(int i = 0; i < m_Hotels.size(); ++i)
{
if(m_Hotel[i].GetName() == a_sName)
return m_Hotel[i]
}
return nullptr; // if non found return return null
}
and add a GetName function to your hotel class which returns a string of its name.
this also allows you to SetName etc.

1) Accessor, mutator: There are plenty of options.
You can create another class like CTouristList (and CHotelList respectively), that wraps the vector, have it referenced from the CHotel class (accessor methods like CTouristList& CHotel::GetTouristList() and const CTouristList& CHotel::GetTouristList() const) and implement methods like CTouristList::Add, CTouristList::Remove, CTouristList::Get, etc.
Or you can add methods like CHotel::AddTourist() directly on the CHotel class.
2) Constructor. Nothing needed in constructor. But for vector<CHotel*> you may need destructor in CResort to explicitly free the CHotel instances. Though not sure why you want to use pointers to CHotel.

You can put the accessor and mutator functions in CTourist just like you would if they were not being stored in a Vector.
To utilize them once they are in CHotel you could add a function in CHotel that returns a pointer to a CTourist.
// Access a CTourist
Hotel.getTourist(1)->setName("Tourist name");
Adding a method that returns the number of tourist that visited a hotel would make it easier to loop through them.
for(int i = o; i < Hotel.touristCount(); ++i)
{
// Do something useful
std:: cout << "Hello " << Hotel.getTourist(i)->getName();
}
In that case your CHotel::touristCount() would be a wrapper around the vector<>.size();
If you do not want code outside of CHotel to have direct access to a CTourist object then create wrapper functions in CHotel that do what you would want to do externally.
i.e.
std::cout << Hotel.getTouristName(1);
instead of
std::cout << Hotel.getTourist(1)->getName();

Related

c++ returning object from function?

Absolute newbie to c++ (and oop) as well.
Just wanted to ask how to return an object from a list (if it exists), by passing a single id to a getter.
My code is as follows:
class Customer
{
private:
unsigned int custNo;
std::string name;
std::string address;
/* .. */
}
class Store
{
private:
std::string storeName;
std::list<Customer *> customerBase;
std::list<Product *> productStock;
std::list<Sale*> sales;
public:
Store(std::string storeName); // constructor
std::string getStoreName();
Customer & getCustomer(unsigned int custId); //METHOD IN QUESTION
/*..*/
// Constructor
Customer::Customer(std::string name, std::string address)
{
//ctor
}
//
Customer & Store::getCustomer(unsigned int custId){
}
I know this might be a farily basic question. Still I would very much appreciate the help. Thanks in advance!
Just wanted to ask how to return an object from a list (if it exists), by passing a single id to a getter.
Pointer is the first thing that you should think when you see "if it exists". This is because the only representation of an object in C++ that can be optional is a pointer. Values and references must always be present. Therefore, the return type of your function should be Customer*, not Customer&:
Customer* Store::getCustomer(unsigned int custId){
...
}
If you need fast retrieval by an id, use a map<int,Customer*> or unordered_map<int,Customer*>. You could do it with a list, too, but the search would be linear (i.e. you would go through the entire list in the worst case).
Speaking of pointers, if you must store pointers to Customer objects, assuming that the objects themselves are stored in some other container, you may be better off using shared_ptr<Customer> in both containers, to simplify resource management.
You can do this but it would be cumbersome as list is not sorted so you have to traverse the list and check each structure for matching id.
Rather you could store these in std::map with ids as their keys...OR much better unordered_map if you really care about performance.
Assuming you have getCustId() public member function in class Customer:
Customer & Store::getCustomer(unsigned int custId){
auto custIt = find_if(customerBase.begin(), customerBase.end(),
[custId](const Customer& c){ return c.getCustId() == custId });
return *custIt;
}

C++ Getting private value with getter

I have a class with private and public members I am trying to use a getter Get_Words() to access the private word member. This all compiles but when the value from dir[NORTH].Get_Words() = "NORTH"; Whenever the word was just a public function without the Get_Words() member function using dir[NORTh].word = "NORTH";
Why isn't the Get_Words assigning the value correctly to word?
class Words
{
public:
static void Set_Words();
string Get_Words();
private:
string word;
}
string Word::Get_Words()
{
return word;
}
...
dir[NORTH].Get_Word() = "NORTH";
and I also tried
dir[NORTH].Get_Word() = Set_Word( string "North");
I'm pretty sure I did the setter wrong but I am new to object oriented programming in c++ and can't figure out the best way to do this.
std::string Get_Word() returns by value, aka it makes a copy of the word and returns it. When you try to assign to it, you are trying to assign to a right hand reference, which is impossible.
A way around this would to return a reference to word:
std::string& Get_Word();
But that is generally considered bad practice as the reference can outlive the class. A better way is to provide a setter along side the getter:
void Set_Word(const std::string& w) {word=w;}
or even better:
template <typename T>
void Set_Word(T&& w) {word=std::foreward<T>(w);}
To get a private value, usually a public get function is implemented.
You want to set the value - usually a public set function is implemented for this task:
void Set_Word(string& newValue) { ... }
Or implement the Getter as returning a reference, as Vlad from Moscow stated.

How to store objects of different class in an array of pointers

I have 3 classes. DrawGameComp' and 'GameComp' where 'GameComp' is the base class of 'DrawGameComp'. I have an array of pointers in Game class which is the controlling class. '
GameComp * components[]; From the main I have to create a dynamic instance of Game and store add new objects of GameComp and DrawGameComp to the array of pointers of type GameComp.
Game Game1(2);
Game1.Add(new GameComponent);
Game1.Add(new DrawableGameComponent);
I'v done this part in the main. Because from the main I have to invoke Add passing object as the parameter. When i store these objects I also want assign an id of 1 to the first object and an id of 2 to the second object. How can i include that too.
The Add() function of my Game class is as follows
void Game::Add(GameComponent*)
{
components[0]=GameComp;
componentCount++;
}
but it give me error. I have tried so hard. But I couldn't. Also how do I invoke the Display() member function of these objects in the Array? is it this way?
components[0]->Display();
The Add method should look like:
void Game::Add(GameComponent* comp)
{
components[componentCount++] = comp;
}
Make sure you zero out componentCount in the constructor.
Using the array:
components[i]->DoSomething();
1) You probably meant to write the following:
void Game::Add(GameComponent* comp)
{
components[componentCount++] = comp;
}
2) components[0]->Display() will work, if display is a member function of GameComponent class.

How to use a std::string with inheritance as parameter?

I'm currently working on a college project with C++ and one of my assignments is to make a social network using inheritance and polymorphism. Currently I have a Node class that is used on a Map and Multimap (both are created manually and not used from the std). The node can hold two variables (key and data for example) and where I'm using it, the first variable can either be a pointer or a string (they let us use std::string).
The problem I'm having is that when I inherit from the "root" class (Object) and use "Object" as a data type for "key", I'm unable to pass a string created with the std as parameter to its constructor, because it doesn't inherit from my Object class. One solution is to implement my own string class and make it inherit from Object, but I was searching for other workarounds.
If there's any problem with the logic above, please tell me as I'm just beginning with C++.
EDIT 1 (some code for my Node):
class TempNode
{
private:
TempNode* next;
Key key;
T value;
public:
TempNode();
explicit TempNode(const Key thisKey, const T thisValue, TempNode* thisNext = NULL)
: key(thisKey)
, value(thisValue)
, next(thisNext)
{
}
inline Key getKey() { return key; }
inline T getValue() { return value; }
inline TempNode* getNext() { return next; }
inline void setNext(TempNode* thisNext) { next = thisNext; }
};
The string or Person types are currently used only in key, but that is with another implementation using templates (which works fine), but my teacher now requires us to apply inheritance to the entire project (to get used to it I guess).
To implement this using inheritance, you think of Key as a data type specifically designed as a key in your map/multimap implementation. Key inherits from Object, but it may provide its own, key-specific functions, such as – for example – a function repr() which generates a representation used by the map for some map-specific operations (maybe as a basis for hashing, or sorting or whatever).
The map/multimap must be used in such a way that the Key objects are stored as pointers (or std::unique_ptr, or std::shared_ptr, or whatever is appropriate), but not as copies of Key objects.
So we have:
struct Object
{
virtual ~Object()
{ }
};
/* Key class. Pointers of this type are inserted
into the map. */
class Key : public Object
{
public:
/* Must be supported by all keys: */
virtual std::string repr() const = 0;
};
We also assume there is a separate definition of Person objects:
struct Person : Object
{
Person(const std::string &name)
: name_(name)
{ }
std::string name_;
};
According to your specification, there are two flavours of Key: One that represents strings and must be initialized using a string, and another one that represents persons and must be initialized by a person pointer (I'll assume that the person-keys do not actually own these pointers, so you need to make sure the person objects they point to stay alive as long as the person-key exists).
We implement this by specializing Key into two derived classes, a PersonKey and a StringKey:
class PersonKey : public Key
{
public:
PersonKey(Person *person_ptr)
: Key() , person_ptr_(person_ptr)
{ }
virtual std::string repr() const
{
if (person_ptr_ != 0)
return std::string("Person/") + person_ptr_->name_;
else
return "<NUL>";
}
private:
Person *person_ptr_;
};
class StringKey : public Key
{
public:
StringKey(const std::string &str)
: Key() , str_(str)
{ }
virtual std::string repr() const
{
return str_;
}
private:
std::string str_;
};
When you make insertions into your map/multimap, you generate Key objects (which you represent as Key* or Key& or std::unique_ptr<Key>). When you want to insert a string, you generate them as StringKey objects, and when you want to insert them as person-pointers, you use PersonKey – but the data type of the key you insert will not reflect the specialization.
Here is an example of a general Key object (implemented as std::unique_ptr<Key>, but you may just use Key* if you are not afraid of memory leaks):
int main()
{
/* General key object: */
std::unique_ptr<Key> mykey;
/* Now it points to a string-key, initialized using
a string, as required: */
mykey.reset(new StringKey("hello"));
std::cout << "repr(mykey) == \""
<< mykey->repr()
<< '"'
<< std::endl;
/* Now the same key object is made to refer to
a person object: */
Person person("me");
mykey.reset(new PersonKey(&person));
std::cout << "repr(mykey) == \""
<< mykey->repr()
<< '"'
<< std::endl;
return 0;
}
Necessary headers for the code above are:
#include <iostream>
#include <memory>
#include <string>
(But memory is only required for my use of std::unique_ptr, which is not actually necessary to solve your problem.)
I think what you are really looking for are templates. Your solution with "root object" won't work as you can see with standard objects and external libraries but also you will not be able to use your containers with primitives (for example person id(as int) as key, and Person class as value).
With templates you can say what type you are going to work with at compile time and compiler will help you to obey your own rules. It can be declared like this:
template<class T1, class T2>
class Map{
T1 key;
T2 value;
(...)
}
Then you can use it more or less like this:
Map<std::String, int> phoneBook;
And compiler will guard you and warn, if you try to add, for example float instead of int, to you Map. But before you start coding I advice you to read some tutorials first, or maybe even some book on c++ in general. But if you want to start with generic right now, you can start her:
http://www.cplusplus.com/doc/tutorial/templates/
The only way you'd be able to store a string in your Object variable was if the string class inherited from your Object class, so you will have to implement your own String class unfortunately.
The real flaw here is that you are taking a Java/C# approach to design, where an Object variable can hold anything. In C++ the proper way to handle such things is through the use of templates, supposing your Map/Multimap/Node only need to hold one specific data type.
If your container needs to be able to hold any arbitrary data type, I would recommend using type erasure, although that can be a bit complicated for a beginner.

Hash table of "classes" (not objects) in C++

I need to make, for my college homework, an interpreter in C++ for a language based on functions (or commands). The interpreter has got to read an input file, extract the words (strings), generate the commands and execute them. All commands are classes which inherit from a common super-class (Command, for example), which's got a virtual method called execute. For each word read from the input file, a command is created and stored in a vector<Command>.
So, I'm thinking of using a hashtable, whose keys are the names of the commands (strings) and whose values are some kind of objects which allow me to create an specific class (or give me access to the constructor of an specific class), to easily create the classes for each word instead of using a chain of if-else-if's.
By now, I'm planning to create a CommandGenerator class with a virtual method called generate which returns a new Command object. The values of my commands hash table will be objects of theCommandGenerator class. So I derive from it many other subclasses for all commands, which return specific new objects derived from Command.
But, does anything like that already exist? Or is there any more elegant way to do that? Is there any kind of object that can be extracted from a class to represent it?
If each command is a subclass of Command, why don't you use a std::vector<Command*> and push pointers to instances of each subclass? Then you can iterate over the vector and call your virtual execute function.
The closest thing you can get about placing classes in a vector is boost::fusion::vector. But can't be filled at runtime, no use on your specific case.
Assuming you can use C++11. If you can define commands as just a execute function, you can do something like:
map<string, function<void()>> cmds = {
make_pair("print1", [](){
cout << "1" << end;
}),
make_pair("print2", [](){
cout << "2" << end;
}),
make_pair("print3", [](){
cout << "3" << end;
})
};
And then put the command on a vector with:
vector<function<void()>> list;
list.push_back(cmds["print1"]);
list.push_back(cmds["print1"]);
list.push_back(cmds["print2"]);
Then just execute with a loop:
for (function<void()>& cmd : list)
cmd();
This should print 112 to screen. But if you care a lot with speed, do a lot of ifs instead.
The basic problem you have is: You have the name of the class as a string and want to create a class with that name. This translation you have to do somehow manually, like you mentioned. This has been discussed here several times, like in Instantiating classes by name with factory pattern or in Looking for a better C++ class factory. The only addition I would make here: use good old macros, because they have a stringize-operator. E.g.:
#include <stdio.h>
#define CREATEOBJ(clss,command) if (strcmp (#clss, command)==0) return new clss;
class Base {
public:
virtual const char *name()=0;
};
class A : public Base {
public:
const char *name() {return "I am an A";}
};
class B : public Base {
public:
const char *name() {return "I am an B";}
};
Base *makeInstance (const char *nm) {
CREATEOBJ(A,nm);
CREATEOBJ(B,nm);
}
int main () {
printf ("%s\n", makeInstance ("A")->name());
printf ("%s\n", makeInstance ("B")->name());
}
of course you can make it nicer by using a hash-table containing the strings and some function-pointer or generator-class pointer, but the idea remains the same: to add a new class, just add one more CREATEOBJ-thingy.