I am having trouble using file I/O to create instances of my classes for a game I am working on. It might well be a dumb question, but I cannot fathom out why the compiler seems to successfully creates the objects from the data stored in the text file and then I can't access them. (I took out the .display() function calls to test this, and added a simple cout << "Object created"; into the constructor to check something had been created.)
But the code trying to access the individual objects gives me Error: "identifier" is undefined when trying to access the objects member functions. I am probably doing something completely wrong and I would appreciate a push in the right direction, I have tried changing the syntax in the while loop for creating the object, but I haven't cracked it yet. Thank you in advance! Code below...
main.cpp
#include <iostream>
#include <string>
#include <fstream>
#include "Attributes.h"
using std::cout;
using std::endl;
using std::cin;
using std::ofstream;
using std::ifstream;
using std::getline;
using std::cerr;
int main() {
std::string line;
ifstream attdata;
attdata.open("data.txt");
if (attdata.is_open())
{
while (attdata.good())
{
getline (attdata, line);
Attributes * line = new Attributes;
}
attdata.close();
}
else cerr << "Unable to open file.";
health.display();
fatigue.display();
attack.display();
skill.display();
defence.display();
skilldef.display();
speed.display();
luck.display();
};
data.txt
health
fatigue
attack
skill
defence
skilldef
speed
luck
Atributes.h
#pragma once
#include <string>
class Attributes
{
public:
Attributes(void);
Attributes(std::string name, std::string shortName, std::string desc, int min, int max);
~Attributes(void);
void display();
private:
std::string m_nameLong;
std::string m_nameShort;
std::string m_desc;
int m_minValue;
int m_maxValue;
};
In C++, all your variables need to be declared by name in your code. You are declaring a bunch of pointer variables all named line in your loop, and then trying to use other named variables like health, fatigue, etc that have not been created.
I don't think you can directly create variables by name from a file like this, but you could read the file and create an array or vector of objects that contain the data from the file. You could pass the string read by getline() into your Attributes constructor, and then store the created pointers in an array or map that you can access later to call methods like display(). If you really want a variable called health in your code, it has to be declared somewhere in the code.
Another minor point is that you are reusing the variable name line (which you previously declared to be a std::string) in the loop scope. This may work, but is confusing and should be avoided. Call your pointer variable something else, like attItem.
For example:
Attributes * attItem = new Attributes(line);
attList.push_back(attItem);
You arent sending any of the information that you received to create the new object. Add a constructor that takes in a string with the information and then initialize Attributes like so:
Atrributes::Attributes(String data){
//parse string and initialize data here
}
Also, I would recommend not making your Attributes object have the same name as the variable that holds the data. Even if it's harmless (and im not sure that it is), its just not very clean.
C and C++ doesn't allow new names of variables to be created at runtime. Thus health in health.display(); can not come from reading a file.
What you can do is have a collection of Attributes (e.g. attList) and a function that finds the appropriate attribute for you:
Attribute health = attList.find("health");
(Or if you prefer to use a map, you could do:
Attribute health = attList["health"];
Another approach of course is to have attributes stored in each object, e.g.
class PlayerBase
{
private:
Attribute health;
Attribute speed;
...
public:
void SetAttribute(const string& name, const Attribute& attr);
};
Then you'd find the right attribute by comparing string name:
void SetAttribute(const string& name, const Attribute& attr)
{
if (name == "health") health = attr;
if (name == "speed") speed = attr;
...
}
Related
I am creating a program that needs to have an array of 100 strings. Each string refers to a mythological god in the game SMITE. This god has 3 important attributes that determine what items the god is allowed to use.
1: ability Class: warrior, mage, guardian, hunter, assassin.
2: Range: Melee or Range.
3: Damage type: Magical or Physical
Basically this program gets a random god, and builds 6 random items from the allowed list it can access based on these attributes.
These attributes will be looked at in order to determine what items the god is allowed to use. there will be around 150 items, and these items are only able to be used by a specific class, range, and damage type.
I have a current solution that works but unfortunately i have to create an entire string array with all of the gods that belong to each type. For example i create an array with 50 magical gods, then an array with 20 mages.
in order to determine which items that god can use i am checking the randomly generated god String against all of the arrays that determine its type, and if it is found then flag that type. I am wondering if it is possible to store these gods as objects with all of these identifiers. Example. The god "Anubis" would have the mage ability class, the ranged range type, and the magical damage type, all stored in the one object that defines Anubis. That way i would not have to create tons of long Arrays full of god names and check them against each other. If this is possible please someone help. I am currently in a programming class for C++ and we have not covered OOP but i am somewhat familiar with it because of python.
const int NUM_GODS = 100;
string god_list[NUM_GODS] = {"Achilles", "Agni", "Ah Muzen Cab", "Ah Puch", "Amaterasu",\
"Anhur", "Anubis", "Ao Kuang", "Aphrodite", "Apollo", "Arachne", "Ares", "Artemis",\
"Artio", "Athena", "Awilix", "Bacchus", "Bakasura", "Baron Samedi",\
"Bastet", "Bellona", "Cabraken", "Camazotz", "Cerberus", "Cernunnos",\
"Chaac", "Chang'e", "Chernobog", "Chiron", "Chronos", "Cu Chulainn",\
"Cupid", "Da Ji", "Discordia", "Erlang Shen"}; //There are many many more but this is just a sample for an idea
With your current goals in mind I would structure your code something like this:
#include <string>
#include <sstream> // needed for stringstream
#include <vector>
#include <iostream>
#include <fstream>
#include <exception>
enum class AbilityType {
WARRIOR,
MAGE,
GUARDIAN,
HUNTER,
ASSASSIN,
HEALER
};
enum class AttackType {
MELEE,
RANGE
};
enum class DamageType {
MAGICAL,
PHYSICAL
};
struct EntityAttributes {
AbilityType abilityType;
AttackType attackType;
DamageType damageType;
};
class Entity {
private:
std::string name_;
EntityAttributes attribs_;
public:
Entity() = default;
explicit Entity(const std::string& name) :
name_(name)
{}
Entity(const std::string& name, EntityAttributes attribs) :
name_(name),
attribs_(attribs)
{}
void assignAttributes(EntityAttributes attribs) {
attribs_ = attribs;
}
std::string getName() const { return name_; }
AbilityType getAbilityType() const { return attribs_.abilityType; }
AttackType getAttackType() const { return attribs_.attackType; }
DamageType getDamageType() const { return attribs_.damageType; }
};
void getAllLinesFromFile(const char* filename, std::vector<std::string>& output) {
std::ifstream file(filename);
if (!file) {
std::stringstream stream;
stream << "failed to open file " << filename << '\n';
throw std::runtime_error(stream.str());
}
std::string line;
while (std::getline(file, line)) {
if (line.size() > 0)
output.push_back(line);
}
file.close();
}
int main() {
try {
// This will store all of the names in from our text file.
std::vector<std::string> names;
getAllLinesFromFile("Names.txt", names);
// This will give us a container of all of our entities with a provided name
// after this container is filled you can go back later and add the addition
// properties, or if you read the properties in from a file as well you can use
// the other Entity constructor to generate all of them with their names and properties
std::vector<Entity> entities;
for (auto& n : names) {
Entity e(n);
entities.push_back(e);
}
// Check our array of Entities
std::cout << "There are " << entities.size() << " entities\n";
for (auto& e : entities) {
std::cout << e.getName() << '\n';
}
} catch( std::runtime_error& e ) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
In the example above the basic text file "Names.txt" has the name of the entity on a single line. I read the file by extracting line by line because if we only did a single cin >> string it would only get the first set of characters until it encountered a white space. So the text file for the entities names look like this:
-Names.txt-
Achilles
Agni
Ah Muzen Cab
Ah Puch
Amaterasu
Anhur
Anubis
Ao Kuang
Aphrodite
Apollo
Arachne
Ares
Artemis
Artio
Athena
Awilix
Bacchus
Bakasura
Baron Samedi
Bastet
Bellona
Cabraken
Camazotz
Cerberus
Cernunnos
Chaac
Chang'e
Chernobog
Chiron
Chronos
Cu Chulainn
Cupid
Da Ji
Discordia
Erlang Shen
This is fairly straight forward and simple to do. Now if you wanted to add to this text file the different attributes that each of these entities are capable of using you can surely do that, however it will make parsing the file a little harder. If this was the case then characters with names that have more than one word would have to be enclosed with some kind of special character such as the quotes " ". I'll give a simple example of what a text file might look like; however the method to read in the text might be similar but the method of parsing the strings within the stored vector will be different.
Achilles Warrior Melee Physical // easy enough only single words to extract from the vector
"Baron Samedi" Mage Range Magical // Here when we parse this line, Baron Samedi is in quotes so that would be our "name" variable then the rest would follow as before.
The enumerated types here are scoped enumerators because of the class declaration this way you can not interchange values like this:
AttackType attType = PHYSICAL; // This will fail to compile.
AttackType attType = DamageType::PHYSICAL; // will still fail to compile.
as they will generate the necessary compiler errors for you.
Also by using vectors above to store your class type, you do not have to explicitly have a specified number of entities and this value does not have to be known at compile time. With this code struture you do not have to use raw arrays and you don't have to worry about going out of bounds with indexing into an array. Here std::vector does all of that for you!
This is just something to think about in your overall design structure. This makes resource management easy, the code is easier to read and debug. It is reusable and should be fairly portable. You can always modify a text file to make changes to your list of characters and their attributes without having to rebuild or recompile your code, all you have to do is modify your text file and run the program again. This also helps to decrease compile and build times.
I have a base class named shapes with derived class of a 3D shape, i.e. Ball or Tetraeder.
My program should read the type of the shape and it's parameters from a text file and write the volume and area to an output text.
#include <fstream>
#include <string>
#include <sstream>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include "Shape.h"
#include "Ball.h"
#include <vector>
using namespace std;
int
main( int argc, char** argv )
{
string input = string(argv[1]);
string output = string(argv[2]);
ifstream file(input);
string line;
string shapename;
int nx = atoi(argv[3]);
int ny = atoi(argv[4]);
int nz = atoi(argv[5]);
while (std::getline(file, line))
{
std::stringstream lineStream(line);
lineStream >> shapename;
int value;
std::vector<int> lineData;
while (lineStream >> value)
{
lineData.push_back(value);
}
Shape * objShape = new shapename(lineData);
objShape -> calc_volume;
objShape -> calc_projection(nx,ny,nz);
std::ofstream f(output);
f << objShape -> get_volume() << " " << objShape -> get_projection << endl;
}
}
My Question is now how can i create an object from a string in a textfile, especially without knowing all derived classes.
It should be possible to add more shapes to the program without changing the code, only by adding new files.
The question is:
My Question is now how can i create an object from a string in a
textfile, especially without knowing all derived classes.
The answer is: you have to know all the derived classes.
C++ does not have reflection. As such all class names are bound at compile time, and this kind of a factory has no choice but to do some variation of:
if (name == "box")
return new Box();
else if (name == "circle")
return new Circle();
// ... etc ... etc ...
There are various different approaches and design patterns that make it possible to automate some of this drudge work, and make this flexible enough to avoid having to explicitly maintain a hardcoded list of all subclasses.
I'll just outline a brief, very brief approach. A very simple one that I've used before, and achieves, pretty much, the same result: a factory that can instantiate a given subclass by name, in a manner where you don't have to manually edit the factory, and add a few more lines of code. The entire process of creating a factory for a new subclass can be neatly wrapped into the process of creating a new subclass, making this a fairly bulletproof, compartmentalized solution.
Consider a simple mechanism for registering a factory for these subclasses:
typedef Shape (*shape_factory_t)();
Shape is your superclass of shapes.
The factory would work something like this:
std::map<std::string, shape_factory_t> all_factories;
void register_factory(const std::string &name, shape_factory_t factory)
{
all_factories[name]=factory;
}
So now you have a map of all your factories. Instead of an endless if statement you have a single map, which you can look up by class name, and call the appropriate factory, something like:
auto iter=all_factories.find(name);
if (iter == all_factories.end())
throw; // Some exception, unknown subclass
return (*iter->second)();
All right, that part's taken care of. The issue now becomes: how to register a factory for each subclass.
Let's say you have an implementation of Circle:
class Circle : public Shape {
class initializer;
// ... other things that make up the Circle
};
Then, in circle.cpp, which implements this subclass:
static Shape *create_circle()
{
return new Circle(); // Add constructor parameters, as appropriate
}
class Circle::initializer {
public:
initializer() {
register_factory("circle", create_circle);
}
};
static initializer initialize_me;
In this manner, the Circle class registers itself with the factory that creates an instance of a given Shape, by class name. You can proceed and implement all other subclasses, individually, without touching the main factory code. You can declare your Box subclass in the same manner, and have it register itself with the factory, which will then automatically know to create a Box class (presumably by invoking the create_box() function), given the name "box".
There is one other detail that needs to be taken care of: initialization order. As you know, the relative initialization order of globally-scoped objects in different translation units is implementation defined, and is otherwise unspecified by C++.
The global std::map of all factory functions must be constructed before all the subclasses try to register themselves, and put themselves into the map, when the application starts.
This is a fairly typical static initialization order fiasco question, for which there are several known solutions. The one explained in this answer should work fine, here.
C++ isn't so flexible. Adding new shapes would mean adding new classes (since you have already made a Shapes, a Ball and a Tetraeder class, I'm assuming you want to make more classes). And if you add new classes, you'll have to change the code, which means you have to recompile.
You have to know what the derived classes are. You're the one who codes them, so you might as well also have a list of them. The best thing you can do about your program being flexible is using header files, which you already seem to be doing anyway.
As for creating an object from a string in a text file (while you know what the 3D object classes are), you can parse the string, read what kind of a shape it wants to make and then do something fairly simple such as this:
//shapeType - a string containing the type of the 3D object
Shape *newShape;
switch(shapeType) {
case "ball":
newShape = new Ball(...); // ... - parameters for the ball dimensions
break;
case "tetraeder":
newShape = new Tetraeder(...); // ... - parameters again
break;
default:
return -1;
}
//and now you can use newShape as you wish
I am trying to write my code without using global variable as most people told me it was a bad habit, so I am changing how my program works.
I am having problem with passing multiple instance of a class to another class. I need to be able to modify the multiple instance of a class in the other class.
Here is what I am trying to do but failing miserably at it :
int main() {
Players *player[6];
//preparing 6 instances of Players() so I can loop through them in another class
for (int i = 0;i<6;i++){
player[i] = new Players();
}
player[0]->name = "fluffy";
Players.h
#ifndef PLAYERS_H_
#define PLAYERS_H_
#include <string>
#include <vector>
class Players {
public:
Players();
virtual ~Players();
std::string name;
bool hand;
int cif;
int id;
std::vector<int> autho;
std::vector<int> collec;
std::vector < std::vector <int> > puppet;
};
#endif /* PLAYERS_H_ */
Players.cpp
#include "Players.h"
Players::Players() {
// TODO Auto-generated constructor stub
name = "";
hand = false;
cif = -1;
id = -1;
}
Players::~Players() {
// TODO Auto-generated destructor stub
}
Now I want to call another class (doesn't matter which) and I want to pass the multi instanced class Players to it so it can read and do modification to the data within these instanced classes.
For example a class with a function that could read player[0]->name and modify it to "sandpaper"
How would you approach this without getting errors from the compiler?
I am open to suggestion for a completely different way to approach this ( I have tried to use struct variables and pass it but I got other problems as well)
thank you,
Kaven
First of all, I'd approach this by using std::vector<Players> (not pointers!). Secondly, I'd just pass this vector by reference to other functions.
I suggest to approach like this:
int main()
{
unique_ptr<vector<Player>> playersVector (new vector<Player>);
for (int i = 0;i<6;i++)
{
playersVector->push_back(Players());
}
playersVector->at(0).name = "fluffy";
}
And then if you want to pass that vector with ownership to some method or class use:
move(playersVector)
If you want have ownership in main class pass by normal pointer:
playersVector.get()
I also suggest using Get/Set methods instead of accessing class fields directly
I am making an airline reservation software and I don't know much about the Visual C++. I am using the simple compiler "TCWIN45". In my program I wish to use file handling and I am succeed to save all the inputs in text file. i need to add search option and modification option. if user choose search and Enter the name then how can I access specific number of lines. because my files contains the record of multiple passengers but I want to show the only one's data. same is the case for modification. I want to access specific location or line and also to overwrite it. please suggest me the most simplest way.
This is my code to save all the record in one text file:
ofstream thefile("ID.txt" , ios::app);
thefile<<"\n\nDay : "<<p1[i].day<<"\nFlight Date : "<<p1[i].date<<"\nFlight Type : "<<p1[i].type<<"\nReturn Date : "<<p1[i].rdate<<"\nDeparture Place : "<<p1[i].from<<"\nDestination : "<<p1[i].to<<"\nClass Type : "<<p1[i].clas<<"\nTime of Flight : "<<p1[i].time<<"\nTitle : "<<p1[i].prefix<<"\nFirst Name : "<<p1[i].fname<<"\nLast Name : "<<p1[i].lname<<"\nDate of Birth : "<<p1[i].dob<<"\nPassport Number : "<<p1[i].ppt_no<<"\nExpiry Date : "<<p1[i].edate<<"\n Contact Number : "<<p1[i].cont<<"\nMeal Type : "<<p1[i].meal<<"\n\n------------------------------";
Ali, this can be done in a flat file if you really want to not use a database. The trick, is to either: 1.) have all records the same size OR 2.) have a "record header" that provides "enough" information to be able to unserialize the record from the hard disk. If you store different kinds of records, "enough" information could be size of the record or a record type for RTTI purposes. I find it useful to also store an ID for each record so that I can store an index table for record offsets.
If you records have varying sizes, then your record's serialization functions have to be able to handle this. In fact, it is trivial to do this.
The index table is a table of file offsets.
typedef uint16_t record_id;
typedef long offset_t;
offset_t indices[ MAX_RECORDS ];
typedef struct _record {
uint16_t type;
uint16_t id;
offset_t next;
offset_t prev;
} record;
typedef struct _header {
uint32_t count;
offset_t first_record;
offset_t deleted_record;
} header;
So to find the position of the record, you find the offset into the file, which is indices[ record_id ]. Adding a record is like adding a node to a linked list, but the nodes are in the file.
Deleting records is a little tricky. You have to use "lazy delete" to delete records and later these deleted records get reused. You can even write a shrink function that will remove all deleted records from the file to free up unused space.
The limitations of this technique is that you can only search by record id. If you have other information, you will need to generate additional data structures to support this.
I have code available that does this in C if you would like a working example. However, doing this from scratch is feasible but NOT WORTH THE EFFORT. Just use a database like Sqlite or MySQL--it will save time!
Example Code
flat-db.c
flat-db.h
test-flat-db.c
From your comments to other answers, it does not seem like the best way for you to do this is to store the data in a text file at all. You will probably want a Reservation class that contains all of the information for the reservation. Then, use some kind of Collection to store all of the reservations. Writing to a text file just adds a huge amount of unnecessary difficulty.
Something like this:
class Reservation
{
std::string day;
std::string date;
std::string flightType;
std::string meal;
/* ... */
};
It would be even better if you made separate classes for each one of the class members (like a Day class, a FlightType class, etc.).
You would then use some kind of Map to access a particular reservation and change its members.
You'll probably want to define a reservation class that represents a single reservation, and a data class, that holds all your data, as a vector of reservations. The data class will want to have a member function that takes a std::ostream by reference, and saves the reservations to a text file, (easiest is one variable per line). It will also want a member function that takes a std::istream by reference and reads in the data from the text file.
The main part of your program would (I'm making TONS of assumptions here) load the file into the data class with the std::istream member function, and asks the user for some sort of ID. You then call a member function of data that checks all of the elements in datas vector until it finds the matching ID (by reference), and lets the user change some members. Then it calls the std::ostream member function again to save the changes.
Streams are handled like this. In this sample, I do not use the data class or a vector, since this question looks suspiciously like homework, but this shows the tricky parts of file handling.
#include <string>
#include <iostream>
#include <fstream>
class Reservation {
std::string ID;
std::string date;
public:
//default constructor
Reservation()
{}
//helpful constructor
Reservation(std::string _id, std::string _date)
:ID(_id), date(_date)
{}
//copy constructor
Reservation(const Reservation& b)
:ID(b.ID), date(b.date)
{}
//move constructor
Reservation(Reservation&& b)
:ID(std::move(b.ID)), date(std::move(b.date))
{}
//destructor
~Reservation()
{}
//assignment operator
Reservation& operator=(const Reservation& b)
{
ID = b.ID;
date = b.date;
return *this;
}
//move operator
Reservation& operator=(Reservation&& b)
{
ID = std::move(b.ID);
date = std::move(b.date);
return *this;
}
//save
std::ostream& save(std::ostream& file) {
file << ID << '\n';
file << date << '\n';
return file; //be in the habit of returning file by reference
}
//load
std::istream& load(std::istream& file) {
std::getline(file, ID);
std::getline(file, date);
return file; //be in the habit of returning file by reference
}
};
int main() {
Reservation reserve; //create a Reservation to play with
{ //load the reservation from loadfile
std::ifstream loadfile("myfile.txt");
reserve.load(loadfile);
}
//display the reservation
reserve.save(cout);
{ //save the reservation to a different file
std::ofstream savefile("myfile2.txt");
reserve.save(savefile);
}
return 0;
}
How can I call a function and keep my constructor private? If I make the class static, I need to declare an object name which the compiler uses to call the constructor, which it cannot if the constructor is private (also the object would be extraneous). Here is the code I am attempting to use (it is not compilable):
I want to keep the constructor private because I will later be doing a lot of checks before adding an object, modifying previous objects when all submitted variables are not unique rather than creating new objects.
#include <iostream>
#include <fstream>
#include <regex>
#include <string>
#include <list>
#include <map>
using namespace std;
using namespace tr1;
class Referral
{
public:
string url;
map<string, int> keywords;
static bool submit(string url, string keyword, int occurrences)
{
//if(Referrals.all.size == 0){
// Referral(url, keyword, occurrences);
//}
}
private:
list<string> urls;
Referral(string url, string keyword, int occurrences)
{
url = url;
keywords[keyword] = occurrences;
Referrals.all.push_back(this);
}
};
struct All
{
list<Referral> all;
}Referrals;
int main()
{
Referral.submit("url", "keyword", 1);
}
What's wrong with having a private constructor and a static factory method?
class Example {
Example() { ... }
public:
static Example CreateExample() {
return Example();
}
};
Based on your main code I think what you're shooting for is a singleton, which would look something like:
class Referral
{
private:
Referral()
{
//...
}
public:
static Referral& instance()
{
static Referral instance_s;
return instance_s;
}
bool submit(string url, string keyword, int occurrences)
{
//...
}
};
Then your call in main would look like:
int main()
{
Referral::instance().submit("url", "keyword", 1);
}
Another possibility is that you're looking to keep a list of Referrals around, in which case you can use a struct and a list of them to accomplish what you're looking for:
struct Referral
{
Referral(string url, string keyword, int occurrences) :
url_m(url), keyword_m(keyword), occurrences_m(occurrences)
{ }
string url_m;
string keyword_m;
int occurrences_m;
};
typedef std::vector<Referral> ReferralSet;
Then your call in main would look like:
int main()
{
ReferralSet set;
set.push_back(Referral("url", "keyword", 1));
}
First, you need to make Submit a static function. Then you can just say
Referral::Submit( url, keyword, occurrences );
without creating a Referral instance.
Then, in your Submit function, you're only creating a temporary Referral object that disappears almost immediately. Probably what you want to do is create an instance dynamically with new. Depending on how you want to manage this, you may want to move the code pushing onto the list into Submit.
Lastly, I would make your list of Referral instances a static member variable rather than how you have it now.
(Also, passing those string arguments by reference would probably be a good idea.)
While the whole code has some smell around, you can make it work just by making slight changes that are unrelated to your question.
To make it compile, I have removed the regex include (I am not using a compiler with C++0x support) and the 'using namespace tr1'. Move the constructor implementation after the definition of the Referral global object. Change the . for a :: in the main function when you refer to a static method.
// changes...
//#include <regex>
...
//using namespace tr1;
...
class Referral {
...
Referral(string url, string keyword, int occurrences); // added ; moved the implementation bellow the Referrals variable definition
...
struct All {
...
} Referrals;
// added constructor implementation here (Referrals global must be defined before use):
Referral::Referral(string url, string keyword, int occurrences)
{
url = url;
keywords[keyword] = occurrences;
Referrals.all.push_back(*this); // added dereference, this is of type Referral*, not Referral
}
int main()
{
Referral::submit("url","keyword",1);
}
Now, from a design point of view the code has a stench to it. If really want to have a global list where you add your Referral objects, consider making it a private static attribute of the Referral class so that you can have a little more control over it (only methods in the Referral class could break the contents). Make all your attributes private and provide only accessors to the functionality that user code will need (read-only access can suffice in most cases). Use initialization lists in your constructors, and initialize all members there in the same order they appear in the class definition.
With all that fixed, it still has some smell to it. The static function creates an instance of the class but the constructor is the one that includes itself in the map (??) It would make a little more sense if the constructor did not interact with the map, and the submit() method would create the object and then include it in the list...
I think you might benefit from expressing what you intend to do, many people here will help you both with design choices and reasons for them.