How to create objects of undefined size, dynamically? - c++

I am trying to create a C++ program where a user enters his choice if he wishes to add another record, and if yes then create a new object for that record.
So if I am including constructors, then how do I create a new object every time the user wants?
(If I give a predefined size to the array of object, then constructor will be called, say 50 times and initialize all 50 objects, while the user may only want to enter less).
Lets just say
class grocerylist
{
float price;
char pname;
public: grocerylist(){.....} //constructor
<some code>
.....
}
main()
{
//grocerylist a[50]; this will call constructor 50 times! which is not desired
}
My guess here is to use the new operator inside a loop, which will break when user doesnt want to enter any more records.But the problem is, it's scope will be destroyed once it comes out of a loop.

Use std::vector and just push grocerylists. Something like:
int main() {
std::vector<grocerylist> list;
[...]
while(user_wants_to_add_another_list) {
list.push(grocerylist(...));
}
}

Related

Can I update an object inside an array?

So I created an object and then added it into an array
Class Item{
...
};
Class Machine{
void setQuantity(int i);
};
Machine::Machine(){
Item items[5];
items[0] = a(int q);
}
I defined the setQuantity() and then tried to setQuantity later in the code, with
items[0].setQuantity(items[0].getQuantity() + 1);
but the quantity of a didn't update. Is it because I can't update a property of an item in an array or why can't the quantity change?
I'm thinking of changing the array into a vector, but I'm wondering if the problem is with the array or not. If it isn't then changing it into a vector won't matter does it?
Thanks in advance!
int Item::getQuantity(){
return quantity;
}
void Item::setQuantity(int q){
quantity = q;
}
items[i].setQuantity(items[i].getQuantity + 1);
I think the problem here is that you are declaring a variable inside a function call a(), which is, based on the code listed, undefined.
int q is the syntax for a variable declaration, but no value has been defined for q.
For each of the 5 items that you create, the default constructor of the class Item is called.
If you want to assign a value to items[0] you can (and probably should), for example, implement an assignment operator and a copy constructor in Item. Or you could store pointers to Item in the array instead of the objects themselves, and then use items[0] = new Item(...) to assign the items.

calling a method to change a private variable in c++

I have 3 classes, Player, Monster and Attack.
Class Player
{
public:
void addMonster(string line);
// ...
}
Class Monster
{
public:
void addAttack();
// ...
private:
vector <Attack> _attacks;
}
Now, addMonster() creates a new monster mn, and then has mn call its method addAttack() to fill the vector _attacks
void Player::addMonster(string line){
//...
Monster mn(line); //creates a new monster
while(condition){
mn.addAttack();
}
}
void Monster::addAttack(){
//...
Attack *att = gio->findAttack(ID) //takes the attack from another part of the program
_attacks.push_back(*att);
}
and it seems to work, if I check the contents of _attacks while inside addAttack(), it is pushing the correct elements in, the size of _attacks changes and evreything,
but when the program returns to addMonster(), the _attacks vector of mn is still (or again) empty, as if it had not called the method at all.
Why?
it's as if the object that gets modified is just a copy of the one calling the method, so the original one is not affected, but then how am I supposed to change that vector of that specific object?
When you create the *att pointer in your addAtack you created it on the stack. Stack variables are deleted when their original function ends and so att is deleted at the and of add attack. One possible workaround for this is to create att on the heap, using the keyword new.

What have I done wrong when coding this array of objects in C++?

I have two classes, PersonnelLists and Employee. I create an instance of PersonnelLists in my main, like so:
int main() {
PersonnelLists example; //Make a personnel list
...
}
PersonnelLists uses a constructor with member initialisation of a list of employees, the number of employees, and the size of the array:
PersonnelLists::PersonnelLists(): List(new Employee[SIZE]), numEmployees(0), arraySize(SIZE){
}
This results in some null empty employees being created (I think?):
Employee::Employee(): employeeNumber(0), name(NULL), department(NULL) {
}
It is at this line that I get an invalid null pointer error.
I am new with C++, fresh off the boat from Java programming. I'm still a novice with pointers, so I'm not quite sure what I'm doing wrong here.
UPDATE:
As requested, here is the class definition of Employee:
#include <iostream>
class Employee {
public:
Employee(); //constructor
Employee(std::string name, std::string deparment);
void Print() const; //Print this employee's details
void setEmployeeNo(int employeeNum);
private:
int employeeNumber;
std::string name;
std::string department;
};
In Java, new Employee[SIZE] creates an array of null references.
In C++, new Employee[SIZE] creates an array of default-constructed instances of Employee. Your default constructor tries to set name and department to NULL. Attempting to initialize a std::string to NULL would give the error you describe.
There's no "null" string in C++, but you could default-construct name and department, which would set them to empty strings:
Employee::Employee(): employeeNumber(0), name(), department() {
Finally, if List can contain a variable number of elements, I would recommend that you use std::vector<Employee> (which is similar to ArrayList<Employee> in Java).
If name and department are std::strings (or a similar string type), then initializing them with NULL (a null character pointer) is invalid.
If I guessed right, you should default-initialize them instead, as:
Employee::Employee(): employeeNumber(0), name(), department() {
}
But we really can't tell without seeing the class definition of Employee.
As others have pointed out, you should use a std::vector instead of an array. That allows you to only
have valid Employee objects in your "list".
I don't know what the actual definitions of your classes are, so it's kind of hard to identify your problem.
But an option in modern C++ of doing that is to use a std::vector<Employee> data member inside PersonnelList class. std::vector can grow dynamically at runtime, using its push_back() method, e.g.
#include <vector> // for std::vector
class Employee
{
....
};
class PersonnelList
{
public:
PersonnelList()
{
// Nothing to do - vector is initialized empty
}
// Get current employee count
size_t Count() const
{
return m_employees.size();
}
// Add a new employee to the personnel
void AddEmployee(const Employee& newEmployee)
{
m_employees.push_back(newEmployee);
}
private:
std::vector<Employee> m_employees;
};
No need to use raw pointers or something similar: robust RAII STL container classes make your code simpler.

Help with Pointers, pointers to objects, and classes

I am looking to be pointed in the right direction.
I have 1 class Event
class Event{
private:
vector<string> Question;
char Mode;// 1 = Ascending 2 = Descending 3 = None
string EventName;
public:
Event(string Name){
EventName = Name;
SetQuestionSize();
SetQuestion();
Mode = 3;
}
void SetName(string NewName){
EventName = NewName;
}
void SetQuestionSize(){
Question.resize(15);
}
int ReturnQuestionSize(){
return Question.size();
}
void SetQuestion(){
Question[0]="Enter ";
Question[1]="1 ";
Question[2]="to ";
Question[3]="sort ";
Question[4]="in ";
Question[5]="ascending ";
Question[6]="order, ";
Question[7]="2 ";
Question[8]="for ";
Question[9]="Descending, ";
Question[10]="or ";
Question[11]="3 ";
Question[12]="to ";
Question[13]="ignore ";
Question[14]=EventName;
}
string ReturnQuestion(int Index){
return Question[Index];
}
/*vector<string> ReturnQuestion(){
return Question;
}*/
void SetMode(char NewMode){
if (NewMode == '0' || NewMode == '1' || NewMode == '2')
Mode = NewMode;
}
char ReturnMode(){
return Mode;
}
string ReturnName(){
return EventName;
}
};
This is will be a member of a second object, which will use Event's functions to store data in Event's members.
The problem I'm having is declaring an array of Event objects in my second object. When researching I came across ways to use an array of pointers to the first object, and some operator '->' that I'm guessing is related to virtual functions.
class WhatTheyWant{
Event *events[2];
public:
WhatTheyWant(){
events[0]= new Event("Miss");
events[1]= new Event("Dodge");
}
};
I'm very ignorant about pointers, and I know I will have to learn them eventually, but are they the best way to go or is there a better.
Since your Event class doesn't have a default constructor, you need to explicitly construct each object with its name, so the way you're doing it currently is the only way to do it.
If you add a default constructor to Event, you can do it in at least two other ways:
If you will always have a (small) fixed number of objects, you can just declare an array of constant size:
Event events[2];
Doing this will automatically construct the objects when WhatTheyWant is created, so you just need to set the names afterwards:
WhatTheyWant() {
events[0].SetName("Miss");
events[1].SetName("Dodge");
}
If you want to have a variable number of events, you can declare a single pointer and dynamically allocate an array of objects:
Event *events;
And you could probably give the number as a parameter to the constructor:
WhatTheyWant(int numEvents) {
events = new Event[numEvents];
for (int i = 0; i < numEvents; i++)
events[i]->SetName("...");
}
Also, not directly related to your question, but your Mode variable would be better modeled using an enumeration instead of a char. Using an enum makes it clearer as to what the variable really means, rather than using values like 0, 1 and 2. For example:
public:
enum ModeType { Ascending, Descending, None };
private:
ModeType Mode;
public:
Event() {
...
Mode = Ascending;
}
void SetMode(ModeType NewMode) {
Mode = NewMode;
}
ModeType ReturnMode() {
return Mode;
}
You can use either array of objects or array of pointers.
Array of objects go like below.
class WhatTheyWant{
Event events[2];
public:
WhatTheyWant()
{
events[0] = Event("Miss");
events[1] = Event("Dodge");
}
};
Note: You need to add default constructor to your event class to compile the above approach.
With the above approach, you do not need to take care of freeing Event objects. Whenever WhatTheyWant object gets destroyed, event objects get destroyed.
Array of pointers approach goes like you mentioned.
But you need to take care of freeing the memory allocated(Unless you use auto_ptr or some c++0x equivalent).
Deletion should happen in destructor like below.
class WhatTheyWant{
Event *events[2];
public:
WhatTheyWant(){
events[0]= new Event("Miss");
events[1]= new Event("Dodge");
}
~WhatTheyWant()
{
delete events[0];
delete events[1];
}
};
In C++, pointers are just like arrays
in your WhatTheyWant class, you define the private member:
Event *events[2];
This is an array of arrays (2D array) with variable length (of arrays) and 2 element in each array.
and the operator '->' is used when you want to access a (member of some kind of object) and that is called an object pointer (a pointer which points to an object) but when you define a normal object variable you use '.' operator.
If you've got the courage and knowledge to use them they are very useful but in general they're dangerous and that's why the new languages tend to go to the managed way.

c++ push_back doesn't work as it is supposed

I have a class symbol_table that has a vector of objects of another class row_st.also I have an enter method where inserts objects of row_st with a passed name into the vector of desired symbol_table.but when I call the enter to enter objects with name :
a;b;c;Iwill get the following result: a,b,c;b,c;c.the first element of vector gets the name of all the entered objects. and the second element also gets the name of the later entries.
class row_st
{
public:
char* name;
type_u type;//int:0,flaot:1;char:2,bool:3,array:
int offset;
symbol_table *next;
symbol_table *current;
};
class symbol_table
{
public:
vector <row_st *> row;
int type;
int header;
int starting_stmt;
int index;
int i;
symbol_table *previous;
symbol_table(){ header=0;
previous=0; index=0;i=0;starting_stmt=0;}
};
and here it is the enter method:
int enter(symbol_table *table,char* name,type_u type){
row_st *t=new row_st;
t->name=name;
t->type=type;
t->offset=table->index;
t->current=table;
table->index++;
t->next=0;
table->row.push_back(t);
table->header +=1;
return table->row.size()-1;
}
the push_backed elements all points to the same address.the new call makes the same row_st every time it is called.what should I do?
You can't use character pointers like that - you need to allocate storage to them. But as you are using C++, you should remove them and replace them with instances of the std::string class, which will manage storage for you.
As Neil Butterworth's answer suggest, the trouble is probably not with this code, but the place where you call it. Using character pointers does not make it impossible to make things work, just harder.
The problem in this case is definitely not with push_back. If you posted the method where you call this code it might be possible to see exactly what goes wrong.