Dynamic object array not working - c++

I have one parent and two children, I want to create a dynamic array that contains the children (not allowed to use vectors). I created the classes and everything, and I get no compilation errors or warnings, but when I try to access a member of the array and print its content, nothing happens.
I'm aware there may be some bad coding style here, but I'm only interested in knowing why the array isn't working. I think it's because I created an array of objects, instead of an array of pointers to objects, I'm not sure.
(I removed the 2nd child from the code because it's irrelevant here)
#pragma warning(disable:4996)
using namespace std;
#include <iostream>
#include <cstdlib>
#include <cctype>
#include "date.h"
#define ADDRESS_SIZE 512
#define NAME_SIZE 128
#define DATE_SIZE 128
class Treatment {
protected:
int treatment_ID;
int patient_ID;
Date treatment_date;
int treatment_costs;
public:
Treatment() {}
Treatment(int treatment_ID, int patient_ID, int treatment_costs, char treatment_date[DATE_SIZE]) {
this->treatment_ID = treatment_ID;
this->patient_ID = patient_ID;
this->treatment_costs = treatment_costs;
this->treatment_date.convert_date(treatment_date);
}
void set_treatment_ID(int treatment_ID) {
this->treatment_ID = treatment_ID;
}
void read_treatment_date(void) {
treatment_date.read_date();
}
void set_treatment_date(char _date[DATE_SIZE]) {
treatment_date.convert_date(_date);
}
void set_patient_ID(int patient_ID) {
this->patient_ID = patient_ID;
}
void set_treatment_costs(int treatment_costs) {
this->treatment_costs = treatment_costs;
}
int get_treatment_ID(void) {
return treatment_ID;
}
int get_patient_ID(void) {
return patient_ID;
}
int get_treatment_costs(void) {
return treatment_costs;
}
};
class Outside_treatment : public Treatment {
private:
int clinic_num;
//class doctor;
public:
Outside_treatment() {}
Outside_treatment(int clinic_num, int treatment_ID, int patient_ID, int treatment_costs, char treatment_date[DATE_SIZE]) :Treatment(treatment_ID, patient_ID, treatment_costs, treatment_date) {
this->clinic_num = clinic_num;
}
void set_clinic_num(int clinic_num) {
this->clinic_num = clinic_num;
}
int get_clinic_num() {
return this->clinic_num;
}
void print_outside_treatment(void) {
cout << "The clinic num is " << clinic_num << "\n";
cout << "The treatment ID is " << treatment_ID << "\n";
cout << "The patient_ID is " << patient_ID << "\n";
cout << "The treatment costs are " << treatment_costs << "\n";
treatment_date.print_date();
cout << " treatment date in compare format is " << treatment_date.get_compare();
}
};
class Dynarray {
private:
Treatment *pa;
int length;
int nextIndex;
public:
Dynarray() {
pa = new Treatment[10];
length = 10;
nextIndex = 0;
}
~Dynarray() {
delete[]pa;
}
void add(Treatment &add) {
Treatment *pnewa;
if (nextIndex == length) {
length += 10;
pnewa = new Treatment[length];
for (int i = 0; i < nextIndex; ++i) {
pnewa[i] = pa[i];
}
delete[]pa;
pa = pnewa;
}
pa[nextIndex++] = add;
}
Treatment &operator[](int index) {
return *(pa + index);
}
};
int main(void) {
Outside_treatment it;
cout << "Enter the patient ID\n";
int p_id;
cin >> p_id;
it.set_patient_ID(p_id);
cin.ignore();
cout << "set treatment date\n";
it.read_treatment_date();
cout << "enter costs\n";
int costs;
cin >> costs;
it.set_treatment_costs(costs);
cout << "enter section num\n";
int sc_num;
cin >> sc_num;
it.set_clinic_num(sc_num);
it.print_outside_treatment();
Dynarray da;
da.add(it);
Treatment *yetanotherpointer = &da[0];
int i = yetanotherpointer->get_patient_ID();
cout << i << endl;
while (1);
};

You are creating an array of Treatment object instances. As such, you cannot store any derived types at all. If you try to assign an object of a derived type to a Treatmentobject, it will get sliced.
Your hunch is correct. Since you are dealing with polymorphic types, you need to store pointers to objects, not actual objects, in the array. Then you can store Treatment* pointers to objects of any derived type, eg:
class Treatment {
...
public:
...
// make the base class destructor virtual so calling
// 'delete' on a base class pointer will invoke derived
// destructors. Otherwise, if a derived class has any
// data members with a non-trivial destructor, you will
// cause leaking. When writing polymorphic classes, it
// is common practice to always define a virtual destructor,
// just in case...
//
virtual ~Treatment() {} // <-- add this
..
};
class Dynarray {
private:
Treatment **pa;
int length;
int capacity;
// prevent copying the array, otherwise you risk
// memory errors if multiple arrays own the same
// objects being pointed at and try to free them
// multiple times. Copying pointers to owned objects
// is not safe, you need a cloning mechanism to
// make deep-copies of derived types so a copied
// array can point to its own objects...
Dynarray(const Dynarray &) {}
Dynarray& operator=(const Dynarray &) {}
public:
Dynarray(int initialCapacity = 10) {
pa = new Treatment*[initialCapacity];
capacity = initialCapacity;
length = 0;
}
~Dynarray() {
for (int i = 0; i < length; ++i)
delete pa[i];
delete[] pa;
}
void add(Treatment *add) {
if (length == capacity) {
Dynarray temp(capacity + 10);
for (int i = 0; i < length; ++i) {
temp.pa[i] = pa[i];
}
Treatment *ptr = temp.pa;
temp.pa = pa;
pa = ptr;
capacity = temp.capacity;
}
pa[length++] = add;
}
Treatment* operator[](int index) {
return pa[index];
}
};
int main(void) {
Outside_treatment *ot = new Outside_treatment;
cout << "Enter the patient ID\n";
int p_id;
cin >> p_id;
ot->set_patient_ID(p_id);
cin.ignore();
cout << "set treatment date\n";
ot->read_treatment_date();
cout << "enter costs\n";
int costs;
cin >> costs;
ot->set_treatment_costs(costs);
cout << "enter section num\n";
int sc_num;
cin >> sc_num;
ot->set_clinic_num(sc_num);
ot->print_outside_treatment();
Dynarray da;
da.add(ot);
Treatment *t = da[0];
int i = t->get_patient_ID();
cout << i << endl;
while (1);
};
On the other hand, if the array doesn't need to own the objects being pointed at, just store the pointers, you can remove the delete loop in the destructor, and the caller is not required to use new to create objects being stored, and making a copy of the array is safe, eg:
class Dynarray {
private:
Treatment **pa;
int length;
int capacity;
public:
Dynarray(int initialCapacity = 10) {
pa = new Treatment*[initialCapacity];
capacity = initialCapacity;
length = 0;
}
// coping is OK since the objects being pointed
// at are not owned by the array!
Dynarray(const Dynarray &src) {
pa = new Treatment*[src.capacity];
capacity = src.capacity;
length = src.length;
for (int i = 0; i < length; ++i) {
pa[i] = src.pa[i];
}
}
Dynarray& operator=(const Dynarray &rhs) {
if (&rhs != this) {
Dynarray temp(rhs);
Treatment **ptr = temp.pa;
temp.pa = pa;
pa = ptr;
capacity = rhs.capacity;
length = rhs.length;
}
return *this;
}
~Dynarray() {
delete[] pa;
}
void add(Treatment *add) {
if (length == capacity) {
Dynarray temp(capacity + 10);
for (int i = 0; i < length; ++i) {
temp.pa[i] = pa[i];
}
Treatment **ptr = temp.pa;
temp.pa = pa;
pa = ptr;
capacity = temp.capacity;
}
pa[length++] = add;
}
Treatment* operator[](int index) {
return pa[index];
}
};
int main(void) {
Outside_treatment ot;
cout << "Enter the patient ID\n";
int p_id;
cin >> p_id;
ot.set_patient_ID(p_id);
cin.ignore();
cout << "set treatment date\n";
ot.read_treatment_date();
cout << "enter costs\n";
int costs;
cin >> costs;
ot.set_treatment_costs(costs);
cout << "enter section num\n";
int sc_num;
cin >> sc_num;
ot.set_clinic_num(sc_num);
ot.print_outside_treatment();
Dynarray da;
da.add(&ot);
Treatment *t = da[0];
int i = t->get_patient_ID();
cout << i << endl;
while (1);
};

Related

Difference in allocating char type and int type in C++

I have a class foo like this:
class foo
{
private:
int* a;
public:
foo()
{
a = new int[4];
cout << "a" << endl;
}
};
When I create new object named foo1 and then I debug, after the allocating line, it yields the result: a 0x005a4580 {-842150451}.
But when I replace all int-s by char-s in class definition, it yields an undesired result:
a 0x005694a0 "ÍÍÍÍýýýý\x6ŒÒ•\x5Ÿ"
that the size of a is now greater than 4.
I dont know what happened. Could you please give me an explanation?
Full code:
#include <iostream>
#include <string>
using namespace std;
class String
{
public:
String(char* data)
{
setSize(0);
while (*(data + size) != '\0')
size++;
this->data = new char[size];
//need to allocate memory for 'data' pointer because 'data' pointer is now on the stack and the data must be on the heap
memcpy(this->data, data, size * sizeof(char));
}
void operator=(String rhs)
{
if (this->data != NULL)
delete[] this->data, data = NULL;
this->data = new char[rhs.getSize()]; //allocate
memcpy(this->data, data, size * sizeof(char));
}
int getSize()
{
setSize(0);
while (*(data + size))
size++;
return size;
}
void setSize(int size)
{
this->size = size;
}
void display()
{
for (int i = 0; i < size; i++)
cout << *(data + i);
}
~String()
{
if (data != NULL)
delete[] data, data = NULL;
}
private:
char* data;
int size;
};
void main()
{
String a("abcd");
String b("1");
a.display();
cout << endl;
cout << b.getSize() << endl;
a = b;
cout << a.getSize() << endl;
system("pause");
}
Whatever you're using to look at a doesn't know how much you allocated. It just knows the type.
In the first version it sees int *, so it shows a single int.
In the second version it sees char *, so it assumes it's a C string and prints whatever is in memory up to the first '\0' byte.

can't return pointer in class [duplicate]

This question already has answers here:
What is The Rule of Three?
(8 answers)
Closed 8 years ago.
#include "C_IntArray.h"
C_IntArray::C_IntArray()
{
m_Array = 0;
m_Length = 0;
}
C_IntArray::~C_IntArray(void)
{
delete m_Array;
m_Length = 0;
}
void C_IntArray::ContructorWithParater(int *intArray, int size)
{
m_Array = new int[size];
m_Length = size;
for (int i = 0; i < size; i++)
m_Array[i] = intArray[i];
}
void C_IntArray::InputArray()
{
cout << "Nhap so luong phan tu: ";
cin >> m_Length;
m_Array = new int [m_Length];
for(int i = 0; i < m_Length; i++)
{
cout << "Nhap phan tu Array[" << i << "] = ";
cin >> m_Array[i];
}
}
void C_IntArray::OutputArray()
{
for(int i = 0; i < m_Length; i++)
cout << m_Array[i] << " ";
}
C_IntArray C_IntArray::Remove(int x)
{
C_IntArray temp;
temp.ContructorWithParater(m_Array, m_Length);
temp.OutputArray();
for(int i = 0; i < temp.m_Length; i++)
{
if(temp.m_Array[i] == x)
{
{
temp.m_Length--;
for(int j = i; j < temp.m_Length; j++)
temp.m_Array[j] = temp.m_Array[j + 1];
}
}
cout << "\n";
temp.OutputArray();
}
cout << "\n";
return temp;
}
File Header
#include <iostream>
using namespace std;
#ifndef _C_IntArray_h
#define _C_IntArray_h
class C_IntArray
{
private:
int *m_Array, m_Length;
public:
C_IntArray();
~C_IntArray();
// khoi tao tham so dau vao
void ContructorWithParater(int *, int);
void InputArray();
void OutputArray();
// xoa phan tu trung
C_IntArray Remove(int );
};
#endif _C_IntArray_h;
File main
#include "C_IntArray.h"
void main()
{
C_IntArray a;
a.InputArray();
int giaTriCanXoa = 5;
C_IntArray b = a.Remove(giaTriCanXoa);
b.OutputArray();
cout << "\n";
a.OutputArray();
system("pause");
}
i have tried to debug my project. the function Remove in class is work, and when i'm debug to return temp it still work, but i'm debug next it return NULL or return 1 array
function Remove in class can't return temp.
if i remove destructor or my temp is static C_IntArray, my project can run.
if I have misspelled the desire to help people fix.
thank you for the attention.
Remove returns a copy of the class, not a pointer. Therefore it is a copy.
Since you do not define a copy constructor or an assignment operator then you'll be using the default copy/assign - which will result in m_Array being deleted more than once.
You can either perform a deep copy of the internal array when copying the class or use Copy on Write and reference counting.
i.e. you will need to add the following functions:
C_IntArray(C_IntArray const& other);
C_IntArray& operator=(C_IntArray const& rhs);
They should allocate new storage for the data in the array and copy the elements from 'other' or 'rhs'. Look up how to write a copy constructor or assignment operator. There will be countless examples online.
There are also memory leaks in your class.
C_IntArray::InputArray() will leak memory since you do not delete m_Array before assigning new memory to it.
It would be better to use a free function for input duties rather than making it a class member - keep the interface of your class minimal and complete.
i.e. move it out of the class:
void InputArray(C_IntArray& dst) {
// ...
}
As others have suggested, just use std::vector.

Can't assign in an array of pointers

My problem is in adaugare function on this line I think persoane[numar_persoane] = pers. Because that line gives me this error. What problem do I have?
I have to use a dynamic array of pointers.
class baze
{
private: int numar_persoane=0;
persoana (*persoane)=(persoana *)malloc(0);
public: baze()
{
persoane = NULL;
}
~baze()
{
delete[] persoane; //???????????
}
void adaugare(persoana pers)
{
numar_persoane++;
realloc(persoane, sizeof(persoana)*numar_persoane);
persoane[numar_persoane] = pers;
};
void afisarealfa()
{
for (int i = 0; i < numar_persoane; i++)
for (int j = i + 1; j < numar_persoane; j++)
if (persoane[i].gnume()>persoane[i].gnume())
{
persoana aux;
aux = persoane[i];
persoane[i] = persoane[j];
persoane[j] = aux;
}
for (int i = 0; i < numar_persoane; i++)
{
cout << "Nume:" << persoane[i].gnume() << endl;
cout << "Varsta" << persoane[i].gan() << endl;
cout << "sex" << persoane[i].gsex();
}
}
This is persoana class:
class persoana
{
private: string nume;
int an;
char sex;
public: void snume(string numebagat)
{
nume = numebagat;
}
string gnume()
{
return nume;
}
void san(int anbagat)
{
an = anbagat;
}
int gan()
{
return an;
}
void ssex(char sexbagat)
{
sex = sexbagat;
}
char gsex()
{
return sex;
}
};
Main:
int _tmain(int argc, _TCHAR* argv[])
{
persoana a;
a.san(1990);
a.snume("Gogu");
a.ssex('m');
cout << "Nume: " << a.gnume() << endl << "Anul nasterii: " << a.gan() << endl << "Sex: " << a.gsex();
baze b;
b.adaugare(a);
return 0;
}
As #simpletron pointed out, malloc(0) is kind of weird. I wasn't even sure it was legal, but per what's the point in malloc(0)?, it is legal albeit implementation defined (it might be NULL, it might be a valid empty region; either way, you can call free on it, and per Is a malloc() needed before a realloc()? you can just skip that malloc;
Using malloc but then delete is not recommended; per Behaviour of malloc with delete in C++, this IS undefined behavior; you should probably be using free to go with realloc instead of delete
You have an off by one error. You should use persoane[numar_persoane-1] = pers;
You probably should set age/sex to some default value in the constructor.
This might be my personal preference, but I dislike copying classes around versus pointer to classes.

Dynamic Memory Allocation for Objects

#include <iostream>
class MyClass
{
public:
MyClass() {
itsAge = 1;
itsWeight = 5;
}
~MyClass() {}
int GetAge() const { return itsAge; }
int GetWeight() const { return itsWeight; }
void SetAge(int age) { itsAge = age; }
private:
int itsAge;
int itsWeight;
};
int main()
{
MyClass * myObject[50]; // define array of objects...define the type as the object
int i;
MyClass * objectPointer;
for (i = 0; i < 50; i++)
{
objectPointer = new MyClass;
objectPointer->SetAge(2*i + 1);
myObject[i] = objectPointer;
}
for (i = 0; i < 50; i++)
std::cout << "#" << i + 1 << ": " << myObject[i]->GetAge() << std::endl;
for (i = 0; i < 50; i++)
{
delete myObject[i];
myObject[i] = NULL;
}
I am wondering why the objectPointer must be inside the for loop, if I take it out and place it right before the for loop, I get nonsensical results. Help would be appreciated, thanks...sorry for the terrible formatting.
myObject[i] = objectPointer;
It should be inside the loop because you are storing a new reference in the array of the pointers. If it is outside the loop, then all the array of pointers point to the same reference. In such scenario, you should be careful while deallocation as all the array of pointers point to the same memory location.

no match for 'operator='

I have built a static stack of structures, and everything works - including creating an array of the structures. However, for some reason I can't set the top of the array to a structure.
In my .cpp file, in my push function, I keep erroring on the following line:
stackArray[top] = newStudent;
The error I am receiving is:
"51: no match for 'operator=' in '(((studentstack)this)->studentstack::stackArray + (+(((unsigned int)((studentstack*)this)->studentstack::top) * 24u))) = ((studentstack*)this)->studentstack::newStudent' "
I am including my code below.
Header file:
#ifndef studentstack_H
#define studentstack_H
#include <iostream>
#include <string>
using namespace std;
class studentstack {
private:
int size; // Stack size
int top; // Top of the Stack
struct student {
int ID;
string Name;
string Address;
double GPA;
};
student * stackArray; // Pointer to the stack
student * newStudent; // Pointer to the new student
public: //Constructor
studentstack(int);
// Copy Constructor
studentstack(const studentstack &);
//Destructor
~studentstack();
//Stack Operaations
void push(string, int, double, string);
void pop(int &);
bool isFull() const;
bool isEmpty() const;
};
#endif
studentstack.cpp
#include <iostream>
#include "studentstack.h"
using namespace std;
studentstack::studentstack(int SIZE) {
stackArray = new student[SIZE];
size = SIZE;
top = -1;
int ID = 0;
double GPA = 0;
}
studentstack::studentstack(const studentstack &obj) {
if (obj.size > 0)
stackArray = new student[obj.size];
else
stackArray = NULL;
size = obj.size;
for (int count = 0; count < size; count++)
stackArray[count] = obj.stackArray[count];
top = obj.top;
}
studentstack::~studentstack() {
delete [] stackArray;
}
void studentstack::push(string name, int id, double gpa, string address) {
if (isFull()) {
cout << "The stack is full.\n";
} else {
top++;
newStudent = new student;
newStudent-> Name = name;
newStudent-> ID = id;
newStudent-> Address = address;
newStudent-> GPA = gpa;
stackArray[top] = newStudent;
}
}
void studentstack::pop(int &id) {
if (isEmpty()) {
cout << "The stack is empty.\n";
} else {
id = stackArray[top].ID;
top--;
}
}
bool studentstack::isFull() const {
bool status;
if (top == size - 1)
status = true;
else
status = false;
return status;
}
bool studentstack::isEmpty() const {
bool status;
if (top == -1)
status = true;
else
status = false;
return status;
}
main.cpp
#include "studentstack.h"
#include <iostream>
#include <string>
using namespace std;
int main() {
string name;
int id, var;
string address;
double gpa;
studentstack s[20];
for(int x =0; x<20; x++) {
cout << "New Student Name: " << endl;
cin >> name;
cout << "ID: " << endl;
cin >> id;
cout << "GPA: " << endl;
cin >> gpa;
cout << "Address: " << endl;
cin >> address;
s.push(name, id, gpa, address)
}
cout << "Popping: "
for(int x = 0; x < 5; x++) {
s.pop(var);
cout <<var;
}
return(0);
}
You might want to cut down the example to a minimal piece of code showing the problem. What it comes down to is that you try to assign a student* to a an element in an array of student objects. A pointer to an object is different to an object:
stackArray[0] = new student(); // does NOT work
stackArray[0] = student();
Note, that object are created in C++ by a constructor and not necessarily involving new. When you construct and object using new you still create an object but you also allocate space for it on the heap. By default, objects are created wherever they are defined. For example, student() creates an object on the stack which is then assigned to an object in the memory of stackArray[0].
Not directly related to your question, but note that your main() cannot work. You declare an array of 20 studentstack elements:
studentstack s[20];
and later on you're doing:
s.push(/* ... */);
s.pop(/* ... */);
That doesn't make much sense. s is not a studentstack. It's an array of studentstacks. Arrays in C++ don't have member functions.