Why Initiate a pointer variable in member function of a class again? - c++

this might a stupid question, but I'm finding it hard to understand why do we need to initiate the pointer variable into the class public member function again, even it is declared in the private section of the class.
This is the basic code of what I'm trying to ask.
class Human{
private:
std::string *name;
int *age;
public:
Human(std::string iname, int iage){
name = new std::string;
age = new int;
*name = iname;
*age = iage;
std::cout<<"Constructor Called \n \n";
}
void display(){
std::cout<<"My name is "<<*name<<" And my Age is "<<*age<<std::endl<<std::endl;
}
~Human(){
delete name;
delete age;
std::cout<<"Destructor Called \n \n";
}
};
int main(){
Human *noor = new Human("Noor", 10);
noor->display();
delete noor;
}
With the above code, the output is working just as expected, just if I comment the dynamic allocation of pointer on Human Constructor . i.e
Human(std::string iname, int iage){
// name = new std::string;
// age = new int;
*name = iname;
*age = iage;
std::cout<<"Constructor Called \n \n";
}
There is a close program warning on command prompt after successful compilation.

Alright, I understood the curve.
It is as in private section the pointer is just been declared and no memory is being allocated to the pointer. So we did allocate the memory for the pointer in constructor.
alternatively, we can directly allocate the memory in the private section as well.
i.e:
class Human{
private:
std::string *name = new std::string;
int *age = new int;
.....
.....
};
Thanks Everyone who responded.

Related

Array of pointers to objects and inherited objects

I am trying to make a program which creates an array of pointers to objects, including inherited objects.
The error I'm getting is on the first bracket ( of the cSClass eg SArray[2] = new cSClass(...); (Last line at the bottom of all the code). The error says "no instance of constructor cSClass::cSClass matches the argument list"
Thank you
All the code is below:
The code for the header of the superclass is:
class sClass;
class sClass {
protected:
std::string name;
int yearBuilt;
public:
// Constructor
sClass(string n = "s1", int yb = 2000) {
name = n;
yearBuilt = yb;
}
// Mutator functions
void setName(string);
void setYearBuilt(int);
// Accessor functions
string getName() {
return name;
}
int getYearBuilt() {
return yearBuilt;
}
// Functions
void getInfo();
};
main class of the superclass:
#include "sClass.h"
using namespace std;
// Mutators
void sClass::setName(string n) {
name = n;
}
void sClass::setYearBuilt(int yb) {
yearBuilt = yb;
}
// Print function
void sClass::getInfo() {
cout << "Name: " << name << endl;
cout << "Year Built: " << yearBuilt << endl;
}
Code for the subclass header:
#include "sClass.h"
class cSClass : public sClass {
protected:
int maxPassengers;
public:
// Constructor
cSClass(int mp = 2000) : sClass() {
maxPassengers = mp;
}
// Mutator functions
void setMaxPassengers(int);
// Accessor functions
int getMaxPassengers() {
return maxPassengers;
}
// Functions
void getInfo() {
}
};
Code for the subclass class:
#include "cSClass.h"
// Mutators
void cSClass::setMaxPassengers(int mp) {
maxPassengers = mp;
}
// Print function
void cSClass::getInfo() {
cout << "Name: " << name << endl;
cout << "Maximum Passengers: " << maxPassengers << endl;
}
And lastly this is the main program code in which i am getting errors where i am trying to fill the array:
#include "sClass.h"
#include "cSClass.h"
int main() {
sClass *SArray[6];
SArray[0] = new sClass(...);
SArray[1] = new sClass(...);
SArray[2] = new cSClass(...);
SArray[3] = new cSClass(...);
}
Edit: Error is at the top, and the arguments I'm passing are
SArray[2] = new cSClass("RMS Queen Mary 2", 2003, 2700);
The constructor needed for this to work is missing:
SArray[2] = new cSClass("RMS Queen Mary 2", 2003, 2700);
It could look like this
class cSClass : public sClass {
cSClass(const std::string& name, int yb, int mp) :
sClass(name, yb),
maxPassengers{mp}
{}
//...
}
You also have some other problems:
You have a non-virtual destructor in the base class. When you delete your objects through a non-virtual base class pointer, only the base class destructor will be called. To fix that, add this to sClass:
virtual ~sClass() = default;
Two definitions of cSClass::getInfo(). Settle for only declaring the function in the class definition and leave the definition of the member function in the .cpp file as-is.
Memory leaks since you don't delete what you've newed. To avoid that problem, it's better to use smart pointers that will delete the object when it goes out of scope, like it will in case an exception is thrown (that you catch). Example:
#include <memory>
//...
std::unique_ptr<sClass> SArray[6]; // or std::array<std::unique_ptr<sClass>, 6> sArray;
SArray[2] = std::make_unique<sClass>();
SArray[2] = std::make_unique<cSClass>("RMS Queen Mary 2", 2003, 2700);
Note: If you instead want a dynamic amount of sClass pointers, use a std::vector:
#include <vector>
//...
std::vector<std::unique_ptr<sClass>> SArray;
SArray.push_back(std::make_unique<sClass>());
SArray.push_back(std::make_unique<sClass>());
SArray.push_back(std::make_unique<cSClass>("RMS Queen Mary 2", 2003, 2700));
SArray.push_back(std::make_unique<cSClass>("RMS Queen Mary 2", 2003, 2700));
There are two fundamental errors in your code!
First, you have provided two definitions for the getInfo member function of the cSClass. If you want to keep the second (out-of-body) definition, then you need to remove the definition part of the (in-body) declaration. So, replace:
// Functions
void getInfo() { /// Note: adding the { } provides a function DEFINITION
}
with this:
// Functions
void getInfo(); // No body provided, so it's JUST a declaration (defined elsewhere)
Then, the calls you make to your constructors cannot have the ... in the argument list (though I'm not sure what you are trying to achieve with this). Simply provide empty argument lists:
SArray[0] = new sClass();
SArray[1] = new sClass();
SArray[2] = new cSClass();
SArray[3] = new cSClass();
or, as there is no argument, you can invoke the 'default' constructor by omitting the argument lists completely:
SArray[0] = new sClass;
SArray[1] = new sClass;
SArray[2] = new cSClass;
SArray[3] = new cSClass;
Also, for completeness, remember to free the memory for the objects you created with new, when you're done with them:
delete SArray[0];
delete SArray[1];
delete SArray[2];
delete SArray[3];
Feel free to ask for further clarification and/or explanation.

Understanding OOP Association and Functions (c++)

There's still a whole load of stuff I do not understand about objects and classes in c++, nothing I have read so far has helped me understand any of it and I'm slowly piecing information together from exercises I manage to complete.
Few main points:
When an object is created from a class, how can you access the name of the object in a function in another class? What type of variable is the name of the object stored in? is it even stored anywhere after it's creation?
My manual has an example of creating an association between two classes;
Aggregationclass
{
public:
...
private:
Partclass* partobject_;
...
};
What does this actually mean? Aggregationclass can access the object partobject in partclass? what variables can be read by aggregationclass from the partclass?
Here is a exercise I'm stuck on from my c++ OOP introductionary class, that expects me to utilize association between classes. (7(2/2)/11)
It consists of uneditable Car class;
#include <iostream>
#include <string>
using namespace std;
class Car
{
public:
void Move(int km);
void PrintDrivenKm();
Car(string make, int driven_km);
private:
string make_;
int driven_km_;
};
Car::Car(string make, int driven_km) : make_(make), driven_km_(driven_km)
{
}
void Car::Move(int km)
{
driven_km_ = driven_km_ + km;
cout << "Wroom..." << km << " kilometers driven." << endl;
}
void Car::PrintDrivenKm()
{
cout << make_ << " car has been driven for" << driven_km_ << " km" << endl;
}
What I have made so far(Person class); I have written most of my questions in comments of this section.
class Person //how do I associate Person class with Car class in a way that makes sense?
{
public:
void ChangeCar(string);
Person(string, string);
int DriveCar(int);
private:
Car* make_;
Car* driven_km_;
string name_;
};
Person::Person(string name, string make) //How do I ensure string make == object created from class Car with same name?
{
Person::name_ = name;
Car::make_ = make_;
}
int Person::DriveCar(int x) //Is this the correct way to use a function from another class?
{
Car::Move(x);
}
void Person::ChangeCar(string y) //this function is wrong, how do I create a function that calls for object from another class with the parameter presented in the call for this function (eg. class1 object(ferrari) = class1 object holds the values of object ferrari from class2?)?
{
Car::make_ = y;
}
and an uneditable main();
int main()
{
Car* dx = new Car("Toyota corolla DX", 25000);
Car* ferrari = new Car("Ferrari f50", 1500);
Person* driver = new Person("James", dx);
dx->PrintDrivenKm();
driver->DriveCar(1000);
dx->PrintDrivenKm();
ferrari->PrintDrivenKm();
driver->ChangeCar(ferrari);
driver->DriveCar(20000);
ferrari->PrintDrivenKm();
return 0;
}
disclaimer: the exercise has been translated from another language, in case of spotting a translation error I failed to notice, please do give notice and I will do my best to fix.
Finished exercise; thank you, u/doctorlove for taking the time with your replies, I can with confidence say that I learned a lot!
class Person
{
public:
void ChangeCar(Car * y);
Person(String name, Car * Car);
int DriveCar(int);
private:
Car * Car_;
int x;
string name_;
string y;
};
Person::Person(string name, Car * Car) : name_(name), Car_(Car)
{
Person::name_ = name;
}
int Person::DriveCar(int x)
{
Car_->Move(x);
}
void Person::ChangeCar(Car * y)
{
Car_ = y;
}
Before talking about pointers, look at the Car class:
class Car
{
public:
void Move(int km);
void PrintDrivenKm();
Car(string make, int driven_km);
private:
string make_;
int driven_km_;
};
You can't get to the private stuff from outside. Period.
You can make (or construct) one
Car car("Zoom", 42);
Since we can see what the constructor does
Car::Car(string make, int driven_km) : make_(make), driven_km_(driven_km)
{
}
it's clear it saves away the string and int in the private member variables make_ and driven_km_.
Now we can call the public functions on this instance:
car.PrintDrivenKm();
car.Move(101);
car.PrintDrivenKm();
So, we've made a car and called some functions.
We could make a car pointer and call its functions too. We need to delete stuff otherwise we leak.
Car * car = new Car("Zoom", 42);
car->PrintDrivenKm();
car->Move(101);
car->PrintDrivenKm();
delete car;
Now to your problems.
You have a started writing a Person class which has two (private) cars (pointers) make_ and driven_km_. The constructor Person(string, string); takes two strings, but main doesn't send it two strings:
Car* dx = new Car("Toyota corolla DX", 25000);
// ...
Person* driver = new Person("James", dx);
It will be sent a string and a Car *; something like this
Person(string name, Car *car);
So perhaps it only needs one car (pointer), Car *car_?
Now as for calling your car pointer, Car has Move method; an instance method not a static method, so call it on an instance:
int Person::DriveCar(int x)
{
//Car::Move(x); //no - which car do we move, not a static on ALL cars
car_->Move(x);
}
Now, if the person wants to change car, you made person take a string:
void Person::ChangeCar(string y)
{
//what goes here?
// you want a Car * from a string...
// we did that before
delete car_; //not exception safe, but ...
car_ = new Car(y);
}
Look back at mian:
driver->ChangeCar(ferrari);
so the calling code will try to send a car (pointer) to swap to. So, get the signature right:
void Person::ChangeCar(Car * y)
{
car_ = y;
}
If you owned the pointers, you would need a destructor to tidy up pointers.
Tell whoever set wrote the code in main to delete their pointers!
Edit:
To re-iterate, in any of the Person you can call the methods on the meber variable car_ functions e.g.
void Person::ChangeCar(Car * y)
{
car_ = y;
y->PrintDriveKm(); //call a method on a car pointer.
car_->PrintDriveKm();
}
This is just the same as calling methods on pointers, as mentioned near the top of my answer.
Go back to
Car* dx = new Car("Toyota corolla DX", 25000);
// ...
Person* driver = new Person("James", dx);
From here, in main, you can call
dx->PrintDrivenKm();
From inside the Person constructor,
Person(string name, Car *car) : name_(name), car_(car)
{
}
You can call methods on car (or car_) inside the braces:
Person(string name, Car *car) : name_(name), car_(car)
{
std::cout << "Hello, " << name << '\n';
car_->PrintDrivenKm();
}
Of note: Car:: means something in the class/structr/namespace/scope Car - but you want to call instance methods, so need an instance name. Use -> to all methods on pointers to instances. Use . to call methods on instances.

C++ Insert into List of Objects

can someone tell me how can i add data into my list of class with C++
please ?
#include <string>
class Person
{
private:
std::string Name;
public:
Person();
~Person();
std::string GetName()
{
return Name;
}
std::string SetName(std::string name)
{
name = Name;
return name;
}
};
void main()
{
list<Person> lp = new list<Person>();
Person p = new Person();
p.Name = "Smith";
lp.insert(p);
}
this is my attempt. Can someone correct me or give me another answer ? Thanks
If by some chance you are using c++11 or greater, consider using:
list.emplace_back()
or
list.emplace_front()
which handles construction and insertion. Of course this would be even better if you had a Person constructor that took a string argument.
Person::Person(std::string& name) { Name = name; }
In which case you could do:
lp.emplace_back("Smith");
list.insert() takes an iterator, i.e. position at which you want to insert the new element.
You can also do
list.push_back(p);
This inserts 'p' at the end of the list.
If you do
list.push_front(p);
insertion happens at the head of list.
First of all, since you're coding in c++ your main function should return an int:
int main()
Second, you're using the new keyword on an object that isn't a pointer, correct that:
// This would perhaps be better:
list<Person*> lp;
Person *p = new Person; // remember to delete p; later
I don't see that you have included <list> header and using std. You need that in order to use list. Or at least write std::list or using std::list;
You are trying to assign to a private class member, either declare it public, or use a setter function:
p->Name = "Smith"; // remember for pointers, use the '->' or *(p).Name
emplace_back() is maybe what you are looking to use (since c++11):
lp.emplace_back(p);
// otherwise, specify an iterator as first argument for insert:
// lp.insert(lp.end(), p);
Why isn't your SetName only void and needs to return something? If you want to return the new Name, you also should have
Name = name;
return Name;
You have switched it.
Also, you don't need any of the new and every main function should return int value (usually 0 if no error occurred).
FIXED CODE:
#include <string>
#include <list>
class Person
{
private:
std::string Name;
public:
//Person();
//~Person();
std::string GetName()
{
return Name;
}
void SetName(std::string name)
{
Name = name;
}
};
int main()
{
std::list<Person> lp;
Person p;
p.SetName("Smith");
lp.push_back(p);
return 0;
}
You need to include lists in order to use them, and you can't assign a private member directly. Also, your declarations are wrong - for this I would recommend some cpp tutorials and reading the documentation.

Copy constractor with memory allocation and deallocation

I have written following piece of code
#include<iostream>
#include<cstring>
using namespace std;
///Driver class
class driver
{
char *name;
int age;
public:
//Default contructor
driver(){}
//Constructor for initialize
driver(int a, char* n)
{
age = a;
int len = strlen(n);
//Allocate memory for name
name = new char[len];
strcpy(name, n);
}
//Copy constructor
driver(const driver &d)
{
name = new char[strlen(d.name)];
strcpy(name, d.name);
age = d.age;
}
void print()
{
cout<<"Name: "<<name<<endl;
cout<<"Age: "<<age<<endl;
}
~driver()
{
if(name != NULL)
{
delete name;
}
}
};
class automobile
{
driver drv;
char* make;
int year;
public:
automobile(driver d, char* m, int y)
{
drv = d;
int len = strlen(m);
make = new char[len];
strcpy(make, m);
year = y;
}
void print()
{
drv.print();
cout<<"Make: "<<make<<endl;
cout<<"Year: "<<year<<endl;
}
~automobile()
{
if(make!=NULL)
{
delete[] make;
}
}
};
int main()
{
driver d(15, "Jakir");
automobile a(d, "Toyta", 1980);
a.print();
return 0;
}
I have to use char* not string and allocate memory dynamically. But when I run the code, there occurs an error of memory leaks. I think it's due to the copy constructor and de-allocation memory of driver class. How to fix the error? Any suggestion is appreciated. Thanks in advance.
There is a lot of stuff wrong with this code, but I will list a few of the big ones.
As smentioned by others, you new char's need to be one bigger than they are.
You default constructor should set name to nullptr.
you have a memory handling error whenever you do an assignment, eg on this line: drv = d; because it calls the default operator=, which is incorrect in your case. Ther eis the Law of the Big Three which loosely states that whenever you need either a (non-trivial) copy constructor, copy assignment operator, or destructor, you'll most likely need to implement the others, too. You need to write an operator=!
Based on existing code, I would expect your operator= to look vaguely like this:
//assignment operator
const driver&operator=(const driver &rhs)
{
if (this==&rhs) return *this;
delete[] this->name;
this->name = new char[strlen(rhs.name)+1];
strcpy(this->name, rhs.name);
this->age = rhs.age;
return *this;
}
Do all that, and your core dump goes away.
PS Please, please just learn to use std::strings, new-ing char arrays and managing the memory yourself is a bad bad move.
name = new char[len+1]; not name = new char[len];
name = new char[strlen(d.name) + 1]; not name = new char[strlen(d.name)];
delete[] not delete
Need to define an assignment operator driver& operator=(const driver &d) in order to follow the rule of three.
Similar changes need to automobile.
However I don't see a memory leak, what makes you think you have one?
In main method you need to do like this,
driver* d = new driver(15, "Jakir");
automobile* a = new automobile (d, "Toyta", 1980);
a->print();
if ( a ) delete a ;
if ( d ) delete d ;
return 0 ;

dynamic memory allocation

how allocate memory dynamically for the array of stucture....
eg:
class students
{
struct stud
{
int r_no;
char name[20];
}*s;
}
how to allocate memory dynamically for *s...
First of all, this is not the way of doing it, as you could use a vector of stud, for instance. With the code as you have it, it would be something like:
class students
{
public:
struct stud ... *s;
students() // ctor
{
s = new stud[100]; // say you have 100 students
// from now on you can use s[0], s[1], etc. in the class
}
};
However, what you should be using is kind of an STL vector or list:
class students
{
public:
struct stud ... ;
std::vector<stud> my_students;
students() // ctor
{
stud aStudent = {0, "Student Name"};
my_students.push_back(aStudent); // add a new student.
}
};
Why the extra wrapping of the struct in a class with nothing but a pointer?
Anyway, in C you'd do something like this:
struct stud
{
int r_no;
char name[20];
} *s;
size_t num_students = 4711;
s = malloc(num_students * sizeof *s);
Then it'd be prudent to go through and make sure all those individial structs are initialized, of course.
If you mean this to be C++, you should write constructors that take care of that, and use a new[] to allocate an array of structures.
You should make use of standard components when you can. Here std::string and std::vector would help you.
struct Student
{
int r_no;
std::string name;
};
typedef std::vector<Student> StudentList;
With such an approach, there is no point in wondering how to dynamically allocate memory. Everything's taken care of !
EDIT:
I simply typedef'ed StudentList because to me, adding more functionality to it would have been unrelated to the question.
Clearly, the last line can be replaced with a true class definition:
class StudentList
{
public:
// Add your own functionalities here
private:
std::vector<Student> m_students;
};
class students
{
public:
students(size_t noOfStudents):m_noOfStudents(noOfStudents)
{
s = new stud[m_noOfStudents];
}
~students()
{
delete s;
}
private:
struct stud
{
int r_no;
char name[20];
}*s;
size_t m_noOfStudents;
}