Can a program user 'name' an inherited object/instance?

Started by
17 comments, last by MikeWhiskyTango 13 years, 9 months ago
Thanks to all replies.
I have no idea regarding STL maps and dictionaries but shall look into them.
The 'camp' looks interesting.

Just to explain why my second post seems to ignore nightcreature's previous response. It was due to my typing and submitting a response to the second query at the same time nightcreature had already submitted his answer. Sorry for the 'crossed wires'.

Just to clarify scope's code, is there any reason to prefix 'string' with the 'std::' if I have 'using namespace std;' as a header?


Advertisement
Quote:Original post by MikeWhiskyTango
Just to clarify scope's code, is there any reason to prefix 'string' with the 'std::' if I have 'using namespace std;' as a header?


No, but you shouldn't really be 'using namespace std;', if you need to make a lot of calls to the same part of the standard library 'using std::whatever;' in a scope that will apply to your frequent calls only is my preferred practise (I'm guessing at least some others would say the same?).

Personally I like to prefix it all with std:: for clarity, the only time I tend to 'using std::' is if I'm doing a lot of input/output using the standard library, or I have a container that is quite a mouthful.


Okay, thanks for that, good to know (re. std etc).
I still have a problem in actually linking the input ID by the player to the actual derived instance. I looked at maps briefly and thought it a bit more advanced than where I am at, but if that is what I really need then...

Here is some of the code. Note that there are many more derived classes than shown and larger switch statements. Tried to boil it down a little.

#include <iostream>#include "cstdio"#include <cctype>#include <ctime>#include <string>  // People is only one of 3 base classes (others are Cars and Buildings)class People {  public:    People(): 	attribute(0)    //std::string ()   ???	   {}	  int attribute;	  std::string id;	 	  void setId(std::string tag)    { id = tag;  }      std::string getId()            { return id; }}; //shopowners is one of many classes derived from Peopleclass Shopowners : public People {  public:    Shopowners()    {	 attribute = 2;     id;    }	};int selection();void datafunc();void populate();void move()   //this interface may not seem a requirement but it is for this kids game{   	char yesno = 'y';	std::cout << "If you want to move a car or person does it have a sticker on it? y/n \n";	std::cin>>yesno;	if (yesno=='y') {datafunc();}	else  selection();}int selection(){	int choice;	std::cout<<"   Which toy do you want to move?\n";	std::cout<< "            1. A person.\n";	std::cout<< "            2. A car.\n";	std::cin>> choice;     switch (choice){   case 1: populate();     //case 2: 	   //this would have several menus. 	   }   return 0;}void populate(){	std::string name; 	std::cout << "Enter a code ID tag, ie; A1 C3 etc\n";	std::cin.ignore(256, '\n');	std::getline (std::cin, name);    	Shopowners fireman; fireman.setId (name);  	// this may then go to events() or some other function etc	}void events (People &personA)      {	  // this contains events and tasks involving the derived classes sent here	// this will also require the id tags for buildings etc.    	}void datafunc ()   //this is an important interface with player{	   std::string idtag;	   std::cout<< "Enter the sticker name on the toy... ";     //Jack, car1 etc ;  	   std::cin.ignore(256, '\n');	   std::getline (std::cin, idtag); 	   	   //	   //   its the code here that I cant work out. //   the 'idtag' entered by the player must link with 1 of a possible 100+ derived instances.//   	   //events(     );  //this must take the chosen instance [matching the idtag] to events() }int main()   {		move();	selection();	datafunc();	// other functions in gameloop	system ("pause");return 0;}



As you can see the main problem is in the void datafunc and linking the input ID tag with the actual object.
Now I can see your problem. Every one of your classes probably has an id member, however this member is bound to an instance of your class, although you want it to be bound to the type of classes (ie. id should be the same for ALL instance of that particular type). One possible way to do this is to change id to be a static member:

class ShopOwners{public:    static std::string id() { return m_id; }private:    static std::string m_id;}std::string ShopOwners::m_id = "ShopOwners";// Inside datafunc()boost::shared_ptr<People> people;if(idtag == Shopowners::getId()) people = boost::make_shared<Shopowners>();else if(...) ....else{   std::cout << "Unknown idtag" << std::endl;    return;}event(*people);


One important thing is that you cannot know the exact type you need during compile time, therefore I create a pointer to the base (using a boost::shared_ptr in this case). If you don't want to use boost::shared_ptr right now, the following would work as well (although I wouldn't recommend it):

People* people = NULL;if(idtag == Shopowners::getId()) people = new Shopowners();...
Thanks for that reply Sis Shadowman.

One thing, you stated that using that last piece of code 'is not recommended'. Any particular reason? I'm assuming its not the accepted practice...
It's because programmers easily forget to delete stuff that was allocated with new/malloc. It becomes more of a problem when you throw exceptions or when you use code that throws (or may throw):

Person* person = new Person(); //< If the constructor of Person throws, then delete is called automaticallyperson->foo(); //< If this function throws then your pointer to the Person instance is gone and you can never get it back again: you have a leak.


If we use a smart pointer like std::auto_ptr or boost::shared_ptr, then the following code never leaks:
std::auto_ptr<Person> person(new Person()); //< If the constructor of Person throws, then delete is called automaticallyperson->foo(); //< If this function throws then person is destructed during stack unwinding, since it's an object on the stack// The destructor of std::auto_ptr takes care of deleting the stored pointer


There are many types of smart_ptrs, and I really recommend using them (when appropriate):
-boost::shared_ptr: All instances of the same boost::shared_ptr share their object, it is only deleted when all instances run out of scope
-std::auto_ptr: One instances owns the stored pointer and takes care of deleting it (there is no sharing)
-com pointers: When you start dealing with COM interfaces, you will notices that they offer AddRef() and Release() functions that you must call when appropriate, a smart com pointer does this for you
-many more
Thanks again for that info, SiS-Shadowman.

My problem is that I have absolutely zero experience with anything such as boost or camp, nor have any knowledge in regards to STL libraries etc. Nevertheless you have shown some very interesting things that I should be pursuing.

I got the program to work after some 'unresolved external' held me up but have yet to verify whether the tagged object was actually passed to events function. I think once I mate it all back together with the main program I will be able to judge whether it has all worked.

I wont mark the topic as resolved just yet in case someone has any other ideas.
Thanks very much.
Apparently still got problems I cant figure out.

If I have two inherited instances derived from People class, ie Shopowners and Policemen I cant seem to get the datafunc function to pass the correct one to randomEvents function. It will always skip the 'if' statment and pass the 'else' statement even when I swap the contents around. It doesnt appear to be matching the contents of idtag with the getrid(). Apart from that the program works.
It should end in randomEvents function and cout 13 or 25. (13 if you chose a policeman and 25 if you chose the shopowner.) In the current set up it will always cout 13 even if I instantiate a shopowner object.

#include <iostream>#include "cstdio"#include <cctype>#include <ctime>#include <string> class People {  public:	      People(): 	 attribute (0)	 {}	 int attribute;	  void setId(std::string tag)    { id = tag;  }                   	  static std::string getid() { return  id; }                                                       	                                                         protected:    static std::string id;};std::string People::id = "Shopowners";class Shopowners : public People {	  public:	      Shopowners()    {	 attribute = 25;     id;	     }	};class Policemen : public People {	  public:	      Policemen()    {	 attribute = 13;     id;	     }	};void selection();void datafunc();void shops();void cops();int renadomEvents();void move()   {   	char yesno = 'y';	std::cout << "If you want to move a car or person does it have a name-sticker on it? y/n \n";	std::cin>>yesno;	if (yesno=='y') {datafunc();}     	else  selection();}void selection(){	int choice;	std::cout<<"   Which toy do you want to move?\n";	std::cout<< "            1. A shopowner.\n";	std::cout<< "            2. A policeman.\n";	std::cout<< "            3. A car.\n";	std::cin>> choice;     switch (choice){   case 1: shops();   case 2: cops();   //case 3 / 4 ,5 ...2043 etc. split up into sub menus	   }  }void shops(){	std::string name; 	std::cout << "Enter the name you want to give him.\n";  	std::cin.ignore(256, '\n');	std::getline (std::cin, name);    	Shopowners ownerOne; ownerOne.setId (name); 	datafunc();	}void cops(){	std::string name; 	std::cout << "Enter the name you want to give him. \n";   	std::cin.ignore(256, '\n');	std::getline (std::cin, name);    	Policemen copperOne; copperOne.setId (name);  	datafunc();	}void randomEvents (People &personA)      {	      std::cout << personA.attribute<<"\n\n";    //currently prog should end here with print out of attribute}void datafunc ()   {	   std::string idtag;	   std::cout<< "Type in the name on the sticker. \n";  	   	   std::getline (std::cin, idtag); 	   	   People* people = NULL;	   if(idtag == Shopowners::getid()) {people = new Shopowners();}   //skipping this ??????????	   else(idtag == Policemen::getid()); {people = new Policemen();}			   randomEvents(*people); }int main()   {		move();	// other functions in gameloop	system ("pause");return 0;}[source/]Appreciate any help, driving me crazy for hours.Thanks.

This topic is closed to new replies.

Advertisement