initializing a global const array of objects with file data

Im creating a c++ console RPG and would like to have a global constant array of objects that stores all the information for the items that the game will use. The trick is I would like to initialize the itemArray with data from a text file. I know you have to initialize constant object data in the constructor but I use the CItem class for other objects that arent constant. So I'm thinking maybe an overloaded constructor is what I need to use. Heres the code for my CItem class and the global I want to create...

my header file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.
.
.
class CItem		
{
     private: string i_name;	
     public:  CItem();		
	      CItem(string fileName); //overloaded constructor
	      void setName(string name);
	      string getName() const;
};

//Would like this global const array of CItem objects
//to be initialized with data from a file.
const CItem itemData[50];
.
.
.


Heres an example of what the text file I want to use would contain...

Copper Sword
Wooden Sheild
Silver Chain
Lucky Ring
Tome of Fire

I tried a few ideas. One involved initializing the global array like this...

1
2
3
4
5
6
const CItem itemData[50] = { CItem(fileName), 
                             CItem(FileName),
                             CItem(FileName),
                             .
                             .
                             .              };


The overloaded constructor sorta worked but all the arrays were filled with the first item in the text file cause I was opening and closing the file stream in the constructor every time. I think I can get it to work that way but having CItem(fileName) typed out 50 times looks really messy. Compiler wont allow global ifstream objects either. Ive been looking in books and websites for the past couple days for a solution. If anyone has any suggestions on how to make this work that would be great. If my question is confusing or you need to see more code just ask. Thanks.

Last edited on
If the contents of the array depend on the contents of a file, then the array can't really be said to be constant, can it?
You should make array non-const and assign it normally while you initialize the rest of your program.
Encapsulate the entire array in the private section of an item container class. Populate that array through the file only. Get rid of setName, and overload the const operator[] of the container.

That will give you an array of items that can be loaded from file but is, for all intents and purposes, read-only to the rest of your application.
Thanks helios and jRaskell for your time and help. The reason I want to use a const array is cause I want all the other objects in my application to be able to look for and copy the information from the array of items but not change it. And I want to load the item information from a file so I dont have hundreds of lines of code that are just initilizations for the const array.

As for the idea about encapsulating the array in the private section of my CItem class(i think thats what you mean jRaskell). I dont want to do that cause I use the CItem class to also store items in a doubly linked list that is the characters' inventory. Heres more code for you to see...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class CItem	//doubly linked list data class
{
     private: string i_name;		//item name
     public:  CItem();			//constructor
	      void setName(string name);
	      string getName();
};

struct item
{
	CItem data;
	int quantity;
	item *prev;
	item *next;
};

typedef item *itemPtr;

class CInventory
{
	private: itemPtr i_head;	//doubly linked list head pointer
	         itemPtr i_tail;        //doubly linked list tail pointer
	         int i_itemCount;	//doubly linked list size counter
	public:  CInventory();	        //constructor
	         CInventory(string fileName);
                 ~CInventory();		//destructor
			 
	         void insert(CItem data);
	         void remove(CItem data);
	         void sortName();
	            
                 void display() const;  //const tells compiler method will change nothing
	         int size() const;
};

const CInventory itemData("gameItems.dat"); //global const doubly linked list

class CParty	
{
   private: string p_name;	//character name
			
   public:  CParty();
 
            static CInventory itemInventory;	//double linked list for item inventory
	    static CInventory gearInventory;    //double linked list for gear inventory
	    static CInventory bookInventory;    //double linked list for book inventory

	    void setName(string);
	    string getName();
};


I ended up just creating a gobal const linked list

const CInventory itemData("gameItems.dat");

Will have to add another method to grab specific items from the list but it will work. I was close to getting the array to work but I got frustrated and have given up on it for now. If your currious as to what I was trying to get do to get the array to work, the explanation is below. If not then just stop reading here. Thanks again for the help and if theres any more suggestions from anybody Im willing to read them. If you see something that my code is lacking or the improper use of something too please tell me. Dont want to get into the habit of doing something wrong.


this Pointer

I had an idea I played around with for a little while. I overloaded the CItem constructor to accept a file name as a parameter. Then I initialized the golbal constant array like this...

 
CItem const itemData[10] = { CItem("item.dat") };


then I played around with the this pointer and came up with...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
CItem::CItem(string fileName)
{
        ifstream inFile;
	inFile.open(fileName.c_str());

	if(inFile.fail())
	{
		cout << "ERROR: Make sure the 'item.dat' file exists" << endl
		     << "       and is installed in the same directory as" << endl
		     << "       the 'game.exe' file." << endl;
		exit(1);
	}
		
	string itemName = "";
	int counter = 0;
	
	while(!inFile.eof())
	{
		getline(inFile, itemName);
		(this+counter)->data = itemName;
                cout << (this+counter) << " " << (this+counter)->data << endl;
		counter++		
	}
	
	inFile.close();
}


this worked...sorta... the screen would display...

0003200 Copper Sword
0003220 Wooden Sheild
0003240 Silver Chain
0003260 Lucky Ring
0003280 Tome of Fire

then when I used used the const array in main()
1
2
3
4
5
6
7
8
9
10
11
int main()
{
     cout << &itemData[0] << " " itemData[0].getName() << endl;
     cout << &itemData[1] << " " itemData[1].getName() << endl;
     cout << &itemData[2] << " " itemData[2].getName() << endl;
     .
     .
     .

     return 0;
}


it displayed...

0003200 Copper Sword
0003220
0003240
0003260
0003280

the addresses matched but the names all got erased. then I realised that when I used

CItem const itemData[10] = {CItem("item.dat") };

after it went through the overloaded constructor for the first data item of the array, it was calling the regular constructor...

 
CItem::CItem() { i_name = ""; }


erasing everything in i_name for the rest of the data items in the array. To test this I made the regular constructor set i_name = "A" and it printed out..

0003200 Copper Sword
0003220 A
0003240 A
0003260 A
0003280 A

Just as I expected. So I comented out i_name = "A" all together so the regular constructor wouldnt change anything. Set by the overload constructor and it still printed out...

0003200 Copper Sword
0003220
0003240
0003260
0003280

erased again, but theres nothing there to erase it since I commented out i_name = "A" in the constrctor...weird. Im sure that im using the this pointer in a way that its not supposed to be used too. Oh well, just gonna stick to the const linked list for now. If you decide to play around with this and figure it out I would love to hear your solution, I would still prefer to used a const array if possible.
Figured it out.

header file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.
.
.
class CItem		//double linked list data class
{
	private: string i_name;		//item name
	public:	 CItem();			//constructor
		 void setName(string name);
		 string getName() const;
};

//non-member functions/variables
const CItem *loadItems(string fileName);
.
.
.


declaration file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
.
.
.
const CItem* loadItems(string fileName)
{
	ifstream inFile;
	inFile.open(fileName.c_str());

	if(inFile.fail())
	{
		cout << "ERROR: Make sure the 'gameItems.dat' file exists" << endl
		     << "       and is installed in the same directory as" << endl
		     << "       the 'game.exe' file." << endl;
		exit(1);
	}
		
	string itemName = "";
	int i = 0;
	
	CItem* items = new CItem[5];


	while(!inFile.eof())
	{
		getline(inFile, itemName);
		items[i].setName(itemName);	
		i++;
	}
	
	inFile.close();


return items;
}
.
.
.


application file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.
.
.
const CItem *itemData = loadItems("gameItems.dat");

int main()
{
	cout << itemData[0].getName() << endl;
	cout << itemData[1].getName() << endl;
	cout << itemData[2].getName() << endl;
	cout << itemData[3].getName() << endl;
	cout << itemData[4].getName() << endl;

        return 0;
}


This works, itemData is a global const array of CItem objects that have been initialized by a file. Was trying to do it this way earlier but kept getting an error saying that itemData had already been initialized. Problem was I was trying to declare const CItem *itemData in the header file. This doestn work, it has to be declared at the top of the application file before the main() function. Thanks all for your help!
There's a possible buffer overflow on line 26. There's no way of knowing how long itemData is. The memory allocated for itemData is never freed.
Topic archived. No new replies allowed.