Dynamically allocated data members in class constructor - c++

I am having issues with trying to figure out how I would turn a data member inside a class (which was originally an int) into a pointer to a dynamically allocated piece of memory.
I know I can do int *num = new int under normal circumstances, but how would I initialize it in a class?
My teacher did an amazing job of not explaining this in the crappiest way possible in class -_-.
This is an example of the class and the constructor.
The header
class Double
{
private:
double *val;
The .cpp
Double::Double()
{
this->equals(0.0);
}
Double::Double(const Double &d)
{
this->equals(d.val);
}
Double::Double(const double &d)
{
this->equals(d);
}
Double::Double(const Interger &i)
{
this->equals(i.toInt());
}
//New overloaded constructor using strings
Double::Double(const string &s)
{
this->equals(s);
}
void Double::equals(const double &d)
{
this->val = d;
}
All I know is I have to make the data member a pointer now, but I have no idea how to create the new memory. I tried looking this up but I could not find an example of how to do DAM inside an actual class for its memory and constructor.
EDIT
Solution was a simpler then I thought.
Double::Double() : val(new double)
{
......
}
just have to do that to every constructor, then change any instance of d.val or this->val to *d.val or *this->val.

SOLUTION TO MY PROBLEM (So the problem is solved)
Solution was simpler then I thought.
Double::Double() : val(new double)
{
......
}
just have to do that to every constructor, then change any instance of d.val or this->val to *d.val or *this->val.
Deconstructors will have to be created to clear the memory though.

Related

Dealing with errors due to different constructors in the code while allocating new memory in object oriented programming

I want to allocate new memory for my class which has some derived classes as well. as I have defined a constructor of type Professor(string name,int age,int publications,int cur_id) memory allocation
per[i] = new Professor; in the main throws error:no matching function for call to 'Professor::Professor().
another error I am getting is candidate: 'Professor::Professor(std::string, int, int, int) expects 4 arguments, 0 provided. please help me how to define a constructor which allocates memory without giving any error, thanks.
ps: I am trying to solve this question
part of my class looks like;
class Person{
protected:
string name;
int age;
public:
Person(string name,int age){
name=name;
age=age;
}
int z=0;
void getdata(){
string m;int n;
cin>>m>>n;
z++;
Person(m,n);
}
void putdata(){
cout<<name<<" "<<age<<endl;
}
};
class Professor: public Person{
public:
int publications;
int cur_id;
Professor(string name,int age,int publications,int cur_id)
:Person(name,age)
{
publications=publications;
cur_id=cur_id;
}
int b=0;
void getdata(){
string a;int b,c;
cin>>a>>b>>c;
b++;
Professor(a,b,c,b);
}
void putdata(){
cout<<name<<" "<<age<<" "<<publications<<" "<<cur_id<<endl;
}
};
class Student:public Person{
public:
int marks[6];
int cur_id;
Student(string name,int age,int arr[6],int cur_id)
:Person(name,age)
{
marks[6]=arr[6];
cur_id=cur_id;
}
int s=0;
void getdata(){
string p;int q;int r[6];
cin>>p>>q;
for(int i=0;i<6;i++){
cin>>r[i];
}
s++;
Student(p,q,r,s);
}
void putdata(){
cout<<name<<" "<<age<<" "<<marks[0]<<" "<<marks[1]<<" "<<marks[2]<<" "<<marks[3]<<" "<<marks[4]<<" "<<marks[5]<<" "<<cur_id<<endl;
}
};
My main function looks like
int main(){
int n, val;
cin>>n; //The number of objects that is going to be created.
Person *per[n];
for(int i = 0;i < n;i++){
cin>>val;
if(val == 1){
// If val is 1 current object is of type Professor
per[i] = new Professor;
}
else per[i] = new Student; // Else the current object is of type Student
per[i]->getdata(); // Get the data from the user.
}
for(int i=0;i<n;i++)
per[i]->putdata(); // Print the required output for each object.
return 0;
}
Your problem has nothing to do with dynamic allocations. You are trying to construct Professors and Students by calling their default constuctor (new Professor / new Student), but they don not have a default constructor.
A default constructor is a constructor that can be called without parameters. You can change existing constructors:
Person(string name = "",int age = 42) : name(name), age(age) {}
And similar for Student. Note that your constructor implementation was wrong. You assigned the parameters to themself but did not initialize the members. The member initialization list is a special place where you can use the same name for member and argument without shadowing.
Alternatively call the constructor with parameters.
Glad to see you are trying to improve your C++ skills. However, there are few things you can do to improve the code quality and style:
per[i]->getdata(); // Get the data from the user. will not work.
You have not defined getdata() with a virtual prefix.
Mark the overloaded methods in your child classes with an override suffix.
The same problem exists for putdata()
Virtual destructor is missing.
Is it valid to create a Person object? I think not. Therefore:
Constructor can be protected.
Person::getdata() can be a pure virtual function.
Person::z is a public member variable.
Member variables in child classes (Student and Professor) are also public.
Mentioned already by #463035818_is_not_a_number that Person *per[n]; is not portable C++.
As suggested by #JulienLopez, generally avoid raw pointers in C++11 and above. Use std::shared_ptr or std::unique_ptr.
I think you're missing the point of a constructor a bit here.
The idea is to have all the data ready to create your instance before hand, and then instanciate your class (either Professor or Student).
So your constructors are good, but you getdata member functions are not.
The easiest way would be for your getdata functions to become free functions (or static member functions, in our case, it's pretty much the same), and they gather the datas needed for construction and instanciate your class. (and a clearer name wouldn't hurt while we're at it)
Professor* createProfessorFromCin()
{
string a;int b,c;
cin>>a>>b>>c;
return new Professor(a,b,c,b+1);
}
and your calling code would just end up as
per[i] = createProfessorFromCin();
for example.
Also, few tips if you plan on improving this piece of code:
use smart pointers, it's not the 90's anymore, your code well be a lot more memory
safe (on the same vein, std::vector or std::array would be nice for the grades too)
If you plan on adding more subclasses of the sort, you should look into the Factory pattern for more OCP-friendly code.
Your Person class needs a virtual destructor (once you will fix your memory issues), otherwise your instances won't get destroyed properly.

Dynamically Allocated Memory Constructor

I'm trying to create a constructor in which the strings are dynamically allocated. I've looked up dynamically allocated memory several times and watched a video about it, but I'm still not 100% sure if I'm understanding the concept. I'm hoping an example specific to what I'm coding will help me out a bit.
These are the private variables I have in my h file:
string* tableID;
int numSeats;
string* serverName;
With that in mind, could someone tell me how I could dynamically allocate memory for the strings in this constructor?
Table::Table(const string& tableID, int numSeats, const string& serverName) {
}
Finally, I would greatly appreciate it if someone could tell me the purpose of dynamically allocated memory. I've see explanations on what dynamically allocate memory is, but I'm not understanding the use of it. Why use dynamically allocated memory? What are the benefits? What are the drawbacks? Thank you!
EDIT: I'm including the rest of the h file. Note that this wasn't created by me, so I can't make changes to it. I can only adhere to it in the cpp file.
#include <string>
#include "party.h"
using std::string;
class Table {
public:
Table();
Table(const string& tableID, int numSeats, const string& serverName);
~Table();
const string* getTableID() const { return tableID; }
int getNumSeats() const { return numSeats; }
const string* getServerName() const { return serverName; }
void decrementTimer() { timer--; }
int getTimer() const { return timer; }
void setTimer(int duration) { timer = duration; }
const Party* getParty() { return party; }
void seatParty(const Party* newParty);
void clearTable() { party = nullptr; timer = 0; }
private:
string* tableID;
int numSeats;
string* serverName;
int timer;
const Party* party;
};
The easiest way to get what you want is to take advantage of the Member Initializer List as this also solves the problem of having the parameters shadow the member variables of the same name.
Table::Table(const string& tableID,
int numSeats,
const string& serverName):
tableID(new string(tableID)),
numSeats(numSeats),
serverName(new string(serverName))
{
}
Allocation is performed with the new operator. Later you will have to release the dynamically allocated memory with the delete operator. Here is documentation on new and the same for delete.
But the use a pointer requirement is bizarre as storing pointers to string makes everything else you with the class do orders of magnitude more difficult. This may be the point of the assignment, but there are better and less-confusing ways to teach this lesson.
The allocated strings must be released. The C++ idiom of Resource Allocation Is Initialization (What is meant by Resource Acquisition is Initialization (RAII)?) suggests you have a destructor to automate clean-up to ensure that it is done. If you need a destructor, you almost always need the other two members of The Big Three (What is The Rule of Three?) and possibly need to take The Rule of Five into account as well.
Whereas because string observes the Rule of Five for you, you should be able to take advantage of the Rule of Zero and implement no special functions.
M.M raises an excellent point in the comments. The above example is too naive. It is probably all you need for the assignment, but it's not good enough for real code. Sooner or later it will fail. Example of how it fails.
First we replace string with something that can expose the error:
class throwsecond
{
static int count;
public:
throwsecond(const string &)
{
if (count ++)
{
count = 0; // reset count so only every second fails
throw runtime_error("Kaboom!");
}
cout << "Constructed\n";
}
~throwsecond()
{
cout << "Destructed\n";
}
};
int throwsecond::count = 0;
Then a simple class that does basically the above with less frills
class bad_example
{
throwsecond * a;
throwsecond * b;
public:
bad_example(): a(nullptr), b(nullptr)
{
}
bad_example (const string& a,
const string& b)
{
this->a = new throwsecond(a);
this->b = new throwsecond(b);
}
~bad_example()
{
delete a;
delete b;
}
};
and a main to exercise it
int main()
{
cout << "Bad example\n";
try
{
bad_example("", "");
}
catch (...)
{
cout << "Caught exception\n";
}
}
Output:
Bad example
Constructed
Caught exception
We have an object constructed and never destroyed.
Since a default constructor has been defined by Table we can, with a compiler that supports the C++11 or a more recent Standard, take advantage of delegated constructors to force destruction of the partially constructed object because it has been fully constructed by the default constructor.
class good_example
{
throwsecond * a;
throwsecond * b;
public:
good_example():
a(nullptr), b(nullptr) //must be nulled or destruction is dicey
{
}
good_example (const string& a,
const string& b) : good_example() // call default constructor
{
this->a = new throwsecond(a);
this->b = new throwsecond(b);
}
~good_example()
{
delete a;
delete b;
}
};
Output:
Good example
Constructed
Destructed
Caught exception
One construct and one destruct. The beauty of this approach is it scales well and adds nothing to the code that you don't already have. The cost is minimal, a and b get initialized and then assigned as opposed to just initialization. Faster code is useless if it doesn't work.
Full example: https://ideone.com/0ckSge
If you can't compile to a modern standard, you wind up doing something like
the next snippet to make sure everything is deleted. It's main sin is it's ugly, but as you add more classes that must be constructed and destroyed it starts getting unwieldy.
Table::Table(const string& tableID,
int numSeats,
const string& serverName):
tableID(NULL),
numSeats(numSeats),
serverName(NULL)
{
try
{
this->tableID(new string(tableID)),
// see all the this->es? don't shadow variables and you won't have this problem
// miss a this-> and you'll have a really bad day of debugging
this->serverName(new string(serverName))
// more here as required
}
catch (...)
{
delete this->tableID;
delete this->serverName;
// more here as required
throw;
}
}
There is probably a way to improve on this and make it more manageable, but I don't know it. I just use newer standards and value semantics (I'd love it if someone can provide a good link that describes this concept) where possible.

C++ Object-oriented programming

I have 1 question because I am pretty curious how to handle with such problem.
I have base class called "Pracownik" (Worker) and 2 subclasses which are made from public Pracownik;
- Informatyk (Informatic)
- Księgowy (Accountant)
Writing classes is easy. Made them pretty fast but I have small problem with main because I am helping friend with program but I was not using C++ for a while. So:
This is my header file "funkcje.h"
#include <iostream>
using namespace std;
class Pracownik
{
private:
string nazwisko;
int pensja;
public:
Pracownik(string="",int=0);
~Pracownik();
string getNazwisko();
int getPensja();
friend double srednia_pensja(int,Pracownik);
};
class Informatyk : public Pracownik
{
private:
string certyfikat_Cisco;
string certyfikat_Microsoft;
public:
Informatyk(string="",int=0, string="", string="");
~Informatyk();
void info();
};
class Ksiegowy : public Pracownik
{
private:
bool audytor;
public:
Ksiegowy(string="",int=0, bool=false);
~Ksiegowy();
void info();
};
double srednia_pensja(int,Pracownik);
These are definitions of my functions "funkcje.cpp"
#include "funkcje.h"
Pracownik::Pracownik(string a,int b)
{
nazwisko=a;
pensja=b;
}
Pracownik::~Pracownik()
{
}
string Pracownik::getNazwisko()
{
return nazwisko;
}
int Pracownik::getPensja()
{
return pensja;
}
Informatyk::Informatyk(string a, int b, string c, string d) : Pracownik(a,b)
{
certyfikat_Cisco=c;
certyfikat_Microsoft=d;
}
Informatyk::~Informatyk()
{
}
Ksiegowy::Ksiegowy(string a, int b, bool c) : Pracownik(a,b)
{
audytor=c;
}
Ksiegowy::~Ksiegowy()
{
}
void Informatyk::info()
{
cout<<"Nazwisko pracownika: "<<Pracownik::getNazwisko()<<endl;
cout<<"Pensja pracownika: "<<Pracownik::getPensja()<<endl;
cout<<"Certyfikat Cisco: "<<certyfikat_Cisco<<endl;
cout<<"Certyfikat Microsoft: "<<certyfikat_Microsoft<<endl;
}
void Ksiegowy::info()
{
cout<<"Nazwisko pracownika: "<<Pracownik::getNazwisko()<<endl;
cout<<"Pensja pracownika: "<<Pracownik::getPensja()<<endl;
cout<<"Audytor: ";
if(audytor)
cout<<"Tak"<<endl;
else
cout<<"Nie"<<endl;
}
double srednia_pensja(int a,Pracownik *b)
{
return 0;
}
And finally main!
#include <iostream>
#include "funkcje.h"
using namespace std;
int main()
{
Pracownik lista[10];
Pracownik *lista_wsk = new Pracownik[10];
Informatyk a("Kowalski1",1000,"Cisco1","Microsoft1");
Informatyk b("Kowalski2",2000,"Cisco2","Microsoft2");
Informatyk c("Kowalski3",3000,"Cisco3","Microsoft3");
Ksiegowy d("Kowalski4",4000,1);
Ksiegowy e("Kowalski5",5000,0);
lista[0]=a;
lista[1]=b;
lista[2]=c;
lista[3]=d;
lista[4]=e;
Informatyk *ab = new Informatyk("Kowalski1",1000,"Cisco1","Microsoft1");
Informatyk *ac = new Informatyk("Kowalski2",2000,"Cisco2","Microsoft2");
Informatyk *ad = new Informatyk("Kowalski3",3000,"Cisco3","Microsoft3");
Ksiegowy *ae = new Ksiegowy("Kowalski4",3000,1);
Ksiegowy *af = new Ksiegowy("Kowalski5",3000,0);
lista_wsk[0]=*ab;
lista_wsk[1]=*ac;
lista_wsk[2]=*ad;
lista_wsk[3]=*ae;
lista_wsk[4]=*af;
for(int i;i<5;i++)
{
lista[i].info();
cout<<endl;
}
cout<<endl;
// for(int i;i<5;i++)
// {
// lista_wsk[i].info();
// }
return 0;
}
Ok and here goes my questions:
I had to create array which is filled with base class objects "Pracownik".
Secondary i had to create array which is full of pointers to class "Pracownik" objects.
(Hope those 2 first steps are done correctly)
Next thing I had to write to array 3 objects of class Informatic and 2 of class Accountant.
So I ve created 5 objects manually and added them into the array in such way array[0]=a;. I guess this is still good.
Next thing i had to create and add similar objects to array of pointers using new. So I ve created array with new and pointers to objects with new. (Hope thats correct 2).
And FINALLY:
I had to use info() on added to array objects.
This is my main question if my array is type "Pracownik" and I want to use function info() from subclasses how should I do that? And how compiler will know if he should use info() from Accountant or Informatic while I am trying to show those information using "for".
In an array of Pracownik, the elements are of type Pracownik. Any information about the objects being of a subclass of Pracownik are lost when you copy the elements into the array.
This is called object slicing and leads to the fact that there is no way to invoke Informatyk::info() on these objects.
If you want to call methods of a subclass, you have to prevent object slicing by storing pointers or references in the array.
As Oswald says in his answer,
Pracownik * lista_wsk = new Pracownik[10];
allocates an array of 10 Pracownik objects. This is probably not what you want. With polymorphism involved, we usually want to deal with pointers or references. Hence, you'd want an array of Pracownik * pointers. Since you already know at compile-time that it will have 10 members, there is no need for a dynamic allocation here. I think you've meant to write
Pracownik * lista_wsk[10];
instead. Now we don't put objects but pointers to objects into the array. For example:
lista_wsk[2] = new Informatyk("Kowalski3", 3000, "Cisco3", "Microsoft3");
And then we can iterate over the items like so:
for (unsigned i = 0; i < 10; ++i)
std::cout << lista_wsk[i]->getNazwisko() << std::endl;
As you have already discovered, it is impossible to call a subclass function member on a superclass object. It would be possible to figure out the actual type at run-time yourslf by means of a cast.
for (unsigned i = 0; i < 10; ++i)
if (Informatyk * info_ptr = dynamic_cast<Informatyk *>(lista_wsk[i]))
info_ptr->info();
dynamic_cast returns a pointer to the target class if this is possible or a nullptr (which evaluates to false, hence the conditional) otherwise. Note however that this is considered very poor style. It is better to use virtual functions. Therefore, add
virtual void
info()
{
// Do what is appropriate to do for a plain Pracownik.
// Maybe leave this function empty.
}
to the superclass and again to the subclass
virtual void
info() // override
{
// Do what is appropriate to do for an Informatyk.
}
The function in the subclass with the same signature is said to override the function inherited from the superclass. Since the function is marked as virtual, the compiler will generate additional code to figure out at run-time what version of the function to call.
If you are coding C++11, you can make the override explicit by placing the keyword override after its type as shown above (uncomment the override). I recommend you use this to avoid bugs that arise from accidental misspelling or other typos.

Calling virtual method of a derived class causes segfaults

I'm trying to make a chess program, but I want to be able to implement different AIs in it. Thus I made a abstract AIgeneric class and the derived class AIrandom off of AIgeneric. Then in my chessAI interface, I create a list of the the AIs, and try to call their getNextMove function and run into a segfault. The code is as below:
class AIgeneric {
public:
virtual int getNextMove(int*, const int &) = 0;
}
class AIrandom : public AIgeneric {
public:
AIrandom();
virtual int getNextMove(int*, const int &);
}
class chessAI {
public:
chessAI();
~chessAI();
void setAI();
int getNextMove(int*, const int &);
private:
vector<AIgeneric*> AIlist;
vector<string> names;
int selectedAI;
};
chessAI::chessAI () {
AIrandom randomAI;
AIlist.push_back(&randomAI);
names.push_back("Random AI");
selectedAI = -1;
}
int chessAI::getNextMove(int * board, const int & color) {
return AIlist[selectedAI]->getNextMove(board, color); //segfault on this line
}
It'd be great if anyone could help me on this problem!
Edit: I do set selectedAI to 0 before calling getNextMove.
In this code:
chessAI::chessAI () {
AIrandom randomAI;
AIlist.push_back(&randomAI);
names.push_back("Random AI");
selectedAI = -1;
}
You store a pointer to a local variable into your vector. After the constructor returns that pointer is no longer valid.
Remember that all local variables are stored on the stack, and the stack is reused in other functions. So when you use the pointer in the vector, it now points to some other functions memory and not the one object you declared.
This can be solved in three ways:
Allocate the object on the heap:
AIlist.push_back(new AIRandom);
Not using pointers at all.
Use smart pointers, such as std::unique_ptr.
You call selectedAI = -1; and then AIlist[selectedAI]->.... What do you expect AIlist[-1] to be, other than undefined behavior?
I expect this is because AIlist[selectedAI] is out of bounds. You can confirm this by replacing it with AIlist.at(selectedAI). Keep in mind that this index is -1 immediately after the constructor...

Trying to store objects in a vector

I'm quite new to C++ and I am trying to store objects inside a std::vector like this:
Event.h:
//event.h
class Event
{
public:
Event();
Event(std::string name);
~Event();
void addVisitor(Visitor visitor);
private:
std::vector<Visitor> m_visitors;
};
Event.cpp:
//event.cpp
Event::Event() :
m_name("Unnamed Event")
{
}
Event::Event(std::string name) :
m_name(name)
{
}
void Event::addVisitor(Visitor visitor)
{
this->m_visitors.push_back(visitor);
}
void Event::listVisitors()
{
std::vector<Visitor>::iterator it;
for(it = this->m_visitors.begin();it != this->m_visitors.end(); ++it)
{
std::cout << it->getName() << std::endl;
}
}
Visitor.h:
//visitor.h
class Visitor
{
public:
Visitor();
Visitor(std::string name);
~Visitor();
std::string getName() const;
void listVisitors();
private:
std::string m_name;
};
Visitor.cpp:
//visitor.cpp
Visitor::Visitor() :
m_name("John Doe")
{
}
Visitor::Visitor(std::string name) :
m_name(name)
{
}
std::string Visitor::getName() const
{
return m_name;
}
main.cpp:
//main.cpp
int main()
{
Event *e1 = new Event("Whatever");
Visitor *v1 = new Visitor("Dummy1");
Visitor *v2 = new Visitor("Dummy2");
e1->addVisitor(*v1);
e1->addVisitor(*v2);
}
If I do it like this I would have to add a copy constructor which would make a deep copy so the object gets copied properly into the vector. I'm looking for a way around it by only storing pointers to the objects in a vector.
I already tried it with std::vector<std::unique_ptr<Visitor> > m_visitors, but then I got some errors when calling addVisitor in main.cpp. Of course I changed the declaration of the class members accordingly.
How would an appropriate declaration of the members and the member function look like to make it work?
Stylistically, if you are passing pointers, just accept pointers as the function arguments.
What's happening in the example code above is that the visitors are getting copied to become function arguments and the pointers you had are unreferenced by anything outside of the main function.
I can't speak to what the errors are that you're seeing as you didn't describe them but it probably has to do with incompatible types.
Just get rid of the news because for these data structures they're unnecessary.
int main()
{
Event e1("Whatever");
Visitor v1("Dummy1");
Visitor v2("Dummy2");
e1.addVisitor(v1);
e1.addVisitor(v2);
}
I would suggest that if you don't know how to use pointers you couldn't possibly want to store them instead (they're a hassle IMO to store in the vector when copying by value works just fine).
The compiler generated copy constructor should work just fine.
No manual deep copy required, because you are quite correctly using std::string, which supports RAII.
However, your main function has three memory leaks — there is no need to use new there anyway, so simply don't.
General rule of thumb:
If, at any time T, you're thinking of introducing more pointers into your code, then you're probably going in the wrong direction.