C++ - Object as a variable in parameters - c++

I am learning C++ through TheNewBostons tutorials and there is one of the programs that I can't figure out how it works. I'll show you the codde before the question.
Main.cpp:
#include <iostream>
#include "People.h"
#include "Birthday.h"
using namespace std;
int main()
{
Birthday birthObject(12,28,1986);
People Ob("Vidar", birthObject);
Ob.printInfo();
}
Birthday.h:
#ifndef BIRTHDAY_H
#define BIRTHDAY_H
class Birthday
{
public:
Birthday(int m,int d,int y);
void prinDate();
private:
int month, day, year;
};
#endif
Birthday.cpp:
#include <iostream>
#include "Birthday.h"
using namespace std;
Birthday::Birthday(int m,int d,int y)
{
month = m;
day = d;
year = y;
}
void Birthday::prinDate()
{
cout << day << "/" << month << "-" << year << endl;
}
People.h:
#ifndef PEOPLE_H
#define PEOPLE_H
#include <string>
#include "Birthday.h"
using namespace std;
class People
{
public:
People(string x, Birthday bo);
void printInfo();
private:
string name;
Birthday dateOfBirth;
};
#endif
People.cpp:
#include "People.h"
#include "Birthday.h"
#include <iostream>
#include <string>
using namespace std;
People::People(string x, Birthday bo)
: name(x), dateOfBirth(bo)
{
}
void People::printInfo()
{
cout << name << " was born on ";
dateOfBirth.prinDate();
}
The thing that I can't figure out is how the objects are used as variables and parameters, and also how you can create an object without calling the constructor (in People.h).

A reasonable question.
What is happening here is that it is calling the copy constructor.
Whenever you declare a class there are several functions which are declared for you, unless you explicitly override them.
Default constructor (if no other constructor is explicitly declared)
Copy constructor if no move constructor or move assignment operator
is explicitly declared. If a destructor is declared generation of a
copy constructor is deprecated.
Move constructor if no copy
constructor, move assignment operator or destructor is explicitly
declared.
Copy assignment operator if no move constructor or move
assignment operator is explicitly declared. If a destructor is
declared generation of a copy assignment operator is deprecated.
Move
assignment operator if no copy constructor, copy assignment operator
or destructor is explicitly declared.
Destructor
Have a look here: http://en.wikipedia.org/wiki/Special_member_functions
In this case the copy constructor is called.

This expression (mem initializer)
dateOfBirth(bo)
in the constructor definition
People::People(string x, Birthday bo)
: name(x), dateOfBirth(bo)
{
}
means a call of the copy constructor of class Birthday to construct object dateOfBirth from object bo.
For example if you would add an explicitly defined copy constructor for class Birthday the following way
class Birthday
{
public:
Birthday(int m,int d,int y);
Birthday( const Birthday &rhs )
{
std::cout << "Birthday::Birthday( const Birthday & ) is called" << std::endl;
month = rhs.month; day = rhs.day; year = rhs.year;
}
void prinDate();
private:
int month, day, year;
};
then when this statement was executed
People Ob("Vidar", birthObject);
you would get message
Birthday::Birthday( const Birthday & ) is called
If you do not define explicitly the copy constructor then the compiler defines it implicitly.

Let's take this step by step:
Birthday birthObject(12,28,1986);
here you're creating a new local variable birthObject of type of Birthday class, passing as parameters (12,289,1986). That invokes the three-parameter constructor of Birthday class
People Ob("Vidar", birthObject);
Here you're creating a local variable Obof type People (note common conventions have class names starting with uppercase, variables starting with lowercase) and passing as parameters ("Vidar" and birthObject).
That invokes the two-parameters constructor of People. This is defined as:
People::People(string x, Birthday bo): name(x), dateOfBirth(bo) { }
Some notes here:
Both parameters are passed by value. This means that the copy constructor (implicit, because you haven't defined any) will be invoked for each of them. (note, as it has been noted in other answers, it is probably best to use const & instead).
attributes are initialized (name, dateOfBirth) (this involves an additional copy constructor for each of them).
Ob.printInfo();
Finally, the printInfo() method of the Ob instance is invoked... which in turn invokes the prinData() method of the Ob's attribute dateOfBirth. Those methods do not have parameters and are invoked on the respective instances.

Related

C++ Destructor: cannot access private member declared in class

I am trying to create a simple program in C++ that creates lists of movies using 2 classes: Movie, which contains details of one movie, and Movies, which contains a name and a vector of Movie objects. The whole point is that the user should only interact with the class Movies, therefore I have chosen to make all the members (both data and methods) of the Movie class private.
I keep getting the following error if I let Movie::~Movie() as it is, but if I comment it in both .h and .cpp, it works just fine.
I have explicitly made Movies class a friend of Movie class, so it can access all its members.
error from Visual Studio Community 2019
Movie.h:
#pragma once
#include<iostream>
#include<string>
class Movie
{
friend class Movies;
private:
std::string name;
std::string rating;
int watchedCounter;
int userRating;
std::string userOpinion;
// methods also private because the user should only interact with the Movies class, which is a friend of class Movie
std::string get_name() const;
Movie(std::string nameVal = "Default Name", std::string ratingVal = "Default Rating", int watchedCounterVal = 0, int userRatingVal = 0, std::string userOpinionVal = "");
~Movie();
};
Movie.cpp:
#include "Movie.h"
// Name getter
std::string Movie::get_name() const
{
return this->name;
}
///*
// Destructor
Movie::~Movie()
{
std::cout << "Movie destructor called for: " << this->name << std::endl;
}
//*/
// Constructor
Movie::Movie(std::string nameVal, std::string ratingVal, int watchedCounterVal, int userRatingVal, std::string userOpinionVal) : name{ nameVal }, rating{ ratingVal }, watchedCounter{ watchedCounterVal }, userRating{ userRatingVal }, userOpinion{userOpinionVal}
{
std::cout << "Movie constructor called for: " << name << std::endl;
}
Movies.h:
#pragma once
#include<iostream>
#include<vector>
#include "Movie.h"
class Movies
{
private:
std::string listName;
std::vector<Movie> vectOfMovies;
static int listNumber;
public:
Movies(std::string listNameVal = "Default User's Movie List ");
~Movies();
std::string get_listName() const;
void addMovie(Movie m);
};
Movies.cpp:
#include<string>
#include "Movies.h"
int Movies::listNumber = 0;
// Constructor
Movies::Movies(std::string listNameVal) : listName{listNameVal}
{
++listNumber;
listName += std::to_string(listNumber);
std::cout << "MovieS constructor called for: " << listName << std::endl;
}
// Destructor
Movies::~Movies()
{
std::cout << "MovieS destructor called for: " << listName << std::endl;
}
std::string Movies::get_listName() const
{
return this->listName;
}
//Add movie to list of movies
void Movies::addMovie(Movie m)
{
this->vectOfMovies.push_back(m);
}
And the main .cpp file:
#include <iostream>
// #include "Movie.h"
#include "Movies.h"
int main()
{
Movies moviesObj;
moviesObj.get_listName();
return 0;
}
If the constructor/destructor is declared as private, then the class cannot be instantiated. If the destructor is private, then the object can only be deleted from inside the class as well. Also, it prevents the class from being inherited (or at least, prevent the inherited class from being instantiated/destroyed at all).
The use of having destructor as private:
Any time you want some other class to be responsible for the life cycle of your class' objects, or you have reason to prevent the destruction of an object, you can make the destructor private.
For instance, if you're doing some sort of reference counting thing, you can have the object (or manager that has been "friend"ed) responsible for counting the number of references to itself and delete it when the number hits zero. A private dtor would prevent anybody else from deleting it when there were still references to it.
For another instance, what if you have an object that has a manager (or itself) that may destroy it or may decline to destroy it depending on other conditions in the program, such as a database connection being open or a file being written. You could have a "request_delete" method in the class or the manager that will check that condition and it will either delete or decline, and return a status telling you what it did. That's far more flexible that just calling "delete".
So, I suggest that you could declare ~Movie(); as public. Then, the problem will be solved.

what is the difference between two types of defining constructors? first one using ":" and the second one defining it in curly braces like functions

I have problem in defining constructors for classes and the way I have defined them earlier, doesn't work here properly.
This is for edx c++ intermediate course. when I try to define a class that inherits from some other class, referring to my base class with a constructor doesn't work properly and so my new class won't be defined correctly. What's the difference between the first use of constructors in the first code (using ":" notation that works properly), and the second one in second code (defining like function, that I have used before properly and doesn't work here)?
I have a base class called Person and a Student class that inherits from the base class. When I try to initialize a Student object that calls one of Person class constructors, it gives wrong answers. I think this is because of the way I define constructors. I make them like functions and initialize variables in curl braces. I have used this method earlier and it was working properly, but it doesn't work here. But the standard method using ":" before curly braces works properly here. I want to know what is the difference between these two?
Person.h:
#pragma once
#include <string>
class Person
{
private:
std::string name;
protected:
int age;
public:
Person();
Person(const std::string & name, int age);
void displayNameAge() const;
};
Person.cpp:
#include "pch.h"
#include "Person.h"
#include <iostream>
//Person::Person()
// : name("[unknown name]"), age(0)
//{
// std::cout << "Hello from Person::Person()" << std::endl;
//}
Person::Person()
{
name = "[unknown name]";
age = 0;
std::cout << "Hello from Person::Person()" << std::endl;
}
Person::Person(const std::string & name, int age)
{
this->name = name;
this->age = age;
std::cout << "Hello from Person::Person(string, int)" << std::endl;
}
//Person::Person(const std::string & name, int age)
// : name(name), age(age)
//{
// std::cout << "Hello from Person::Person(string, int)" << std::endl;
//}
void Person::displayNameAge() const
{
std::cout << name << ", " << age << std::endl;
}
Student.h:
#pragma once
#include "Person.h"
class Student : public Person
{
private:
std::string course;
public:
Student();
Student(const std::string & name, int age, const std::string & course);
void displayCourse() const;
};
Student.cpp:
#include "pch.h"
#include "Student.h"
#include <iostream>
Student::Student()
{
course = "[unassigned course]";
std::cout << "Hello from Student::Student()" << std::endl;
}
// first method: the right one
//Student::Student(const std::string & name, int age, const std::string & course)
// : Person(name, age), course(course)
//{
// std::cout << "Hello from Student::Student(string, int, string)" << std::endl;
//}
// second method: the wrong one
Student::Student(const std::string & name, int age, const std::string & course)
{
Person(name, age);
this->course = course;
std::cout << "Hello from Student::Student(string, int, string)" << std::endl;
}
void Student::displayCourse() const
{
std::cout << course << std::endl;
}
Main.cpp:
#include "pch.h"
#include "Student.h"
int main()
{
// Create a Student object using the no-argument constructor.
Student Student1;
Student1.displayNameAge();
Student1.displayCourse();
// Create a Student object using the parameterized constructor.
Student Student2("Jane Smith", 25, "Physics");
Student2.displayNameAge();
Student2.displayCourse();
return 0;
}
expected result:
Hello from Person::Person()
Hello from Student::Student()
[unknown name], 0
[unassigned course]
Hello from Person::Person(string, int)
Hello from Student::Student(string, int, string)
Jane Smith, 25
Physics
actual result:
Hello from Person::Person()
Hello from Student::Student()
[unknown name], 0
[unassigned course]
Hello from Person::Person()
Hello from Person::Person(string, int)
Hello from Student::Student(string, int, string)
[unknown name], 0
Physics
Initializer List
What you are missing is the initializer list.
Type::Type(Parameters)
: member1(init) // This is the initializer list
, member2(init)
{
Your code
}
If you do not explicitly provide one then the compiler will do it for you using the default constructor for the parent class then a call to the default constructor for each member.
So lets look at your class.
Student::Student(const std::string & name, int age, const std::string & course)
{
// Code
}
That is what you wrote. But this is what the compiler implemented.
Student::Student(const std::string & name, int age, const std::string & course)
: Person()
, course()
{
// Code
}
So because you did not do anything the compiler added it calls to the Person default constructor and course (std::string) default constructor.
Now the problem comes if your base class does not have a default constructor. Then the compiler can not add the appropriate calls and will generate a compiler error.
But there is also the issue that the way you are writing this is very inefficient as you are basically initializing all the members twice. Your calling the default constructor then in the Code section you are re-initializing the members with another value.
Student::Student(const std::string & name, int age, const std::string & course)
: Person(name, age)
, course() // Initialize it to empty here.
{
course = "[unassigned course]"; // Re-Initialize it with info.
}
You could simply do it once:
Student::Student()
: Person() // Note person must have a default constructor for this to work.
, course("[unassigned course]")
{}
Temporary Object
Student::Student(const std::string & name, int age, const std::string & course)
{
Person(name, age);
// CODE.
}
This is not doing what you think.
Lets add the initializer list.
Student::Student(const std::string & name, int age, const std::string & course)
: Person()
, course()
{
Person(name, age); // This is creating a person object localy.
// the person object has no name so is a
// temporary variable and goes out of scope
// at the ';'. So it is created and destroyed
// in place before other code is executed.
//
// This does not help initialize the class.
// It is creating a completely different
// and independent object.
// CODE.
}
You can see the execution here:
Hello from Person::Person() // Init parent
Hello from Person::Person(string, int) // Init the temp object.
// If you put a print in the destructor
// You will also see that executed
// Before the Student
// This is also why the object has "unknown name" and 0 age.
Hello from Student::Student(string, int, string) // Now we init the student
[unknown name], 0
Physics
Advice
Is there a valid scenario where you want initialized versions of the object? Personally I think not (if there are then ignore this) so get rid of the default constructors of Person and Student. Then you can not create uninitialized Students or `People.

How to create an object with the constructor with parameter

For some reason whenever I try running my code it always call the default constructor but it should be calling the constructor with parameters.
#include "pokemon.h"
int main()
{
int choice;
cout<<"input 1 2 or 3"<<endl;
cin>>choice;
if(choice==1||choice==2||choice==3)
{
pokemon(choice);
}
}
in my headerfile i have
#include <iostream>
#include <string>
#include <stdlib.h>
#include <time.h>
using namespace std;
class pokemon{
public:
pokemon();//default constructor
pokemon(int a);
~pokemon();//desconstructor
pokemon(const pokemon& c);
void train();
void feed();
bool isnothappy();
string getName();//accessor for the name
int getPowerlevel();//accessor for the power level
string getColor();//accessor for the color
string getType();//accessor
int getHappylevel();//accessor
static int getNumObjects();
void set_type(string);//mutator
void set_color(string);//mutator
void set_power_level(int);//mutator
void set_happy_level(int);//mutator
void set_name(string);//mutator
private:
string name;
string color;
string type;
int power_level;
int happy_level;
static int numberobject;
};
and in my other .cpp file i have
int pokemon::numberobject=0;//initialize static member variable
pokemon::pokemon(){//default constructor
name="pikachu";
color="yellow";
type="electric";
power_level=0;
happy_level=1;
cout<<"The default constructor is being called"<<endl;
++numberobject;
}
pokemon::pokemon(int a)
{
if(a==0)
{
name="Pikachu";
color="yellow";
type="electric";
power_level=1;
happy_level=1;
}
else if(a==1)
{
name="Bulbasaur";
color="green";
type="grass";
power_level=1;
happy_level=1;
}
else if(a==2)
{
name="Charmander";
color="red";
type="fire";
power_level=1;
happy_level=1;
}
else if(a==3)
{
name="Squritle";
color="blue";
type="water";
power_level=1;
happy_level=1;
}
cout<<"Congratulations you have chosen "<<getName()<<". This " <<getColor()<<" "<<getType()<<" pokemon is really quite energetic!"<<endl;
++numberobject;
}
pokemon::~pokemon()
{
//cout<<"the destructor is now being called"<<endl;
//cout<<"the number of objects before the destructor is "<<pokemon::getNumObjects()<<endl;
--numberobject;
cout<<"Now you have a total number of "<<pokemon::getNumObjects()<<endl;
}
pokemon::pokemon(const pokemon& c)//copy constructor
{
name=c.name;
color=c.color;
type=c.type;
power_level=c.power_level;
happy_level=c.happy_level;
++numberobject;
}
I have both my constructors declared and defined in my other files but this darn thing always calls the default constructor
This code:
pokemon(choice);
means the same as:
pokemon choice;
It declares a variable called choice of type pokemon, and there are no arguments given to the constructor. (You're allowed to put extra parentheses in declarations in some places).
If you meant to declare a variable where choice is a constructor argument then you have to write:
pokemon foo(choice);
If you meant to create a temporary object (which will be immediately destroyed) with choice as argument, you can write (pokemon)choice;, or pokemon(+choice);, or since C++11, pokemon{choice};.
This issue with ambiguity between declarations and non-declarations can arise any time a statement begins with a type-name followed by (. The rule is that if it is syntactically correct for a declaration then it is treated as a declaration. See most-vexing-parse for other such cases.

C++ Need help using custom constructor

new to c++ and cant figure out why visual studio doesn't like my "HealthProfile person.setFirstName(first)" line of code. The error is with "person" and the error is no default constructor. It's probably something painfully obvious, but my code is almost identical from the code in my book. Thanks in advance!
main:
#include <iostream>
#include "HealthProfile.h"
using namespace std;
int main()
{
string first;
HealthProfile person;
cout << "Enter first name" << endl;
getline(cin,first);
person.setFirstName(first);
}
header:
#include <string>
using namespace std;
class HealthProfile
{
public:
HealthProfile(string, string, string, int, int, int, int, int);
void setFirstName(string);
string getFirstName();
void setLastName(string);
string getLastName();
};
function:
#include <iostream>
#include "HealthProfile.h"
using namespace std;
HealthProfile::HealthProfile(string first, string last, string g,
int m, int d, int y, int h, int w)
{
setFirstName(first);
setLastName(last);
setGender(g);
setMonth(m);
setDay(d);
setYear(y);
setHeight(h);
setWeight(w);
}
void HealthProfile::setFirstName(string first)
{
firstName = first;
}
string HealthProfile::getFirstName()
{
return firstName;
}
void HealthProfile::setLastName(string last)
{
lastName = last;
}
string HealthProfile::getLastName()
{
return lastName;
}
There is nothing wrong with setFirstName().
The issue is that you've declared a constructor that takes three strings and five ints, this removes the default constructor which you are using when you call HealthProfile person
The solution is to either use the HealthProfile cosntructor and pass it three strings and five ints, or to declare and define a constructor that takes no parameters by adding HealthProfile(){} to the header.
This line in main:
HealthProfile person;
Declares an instance of the HealthProfile class using a default constructor. You've not declared a default constructor. Creating your own custom constructor prevents a default constructor from being implicitly created for you. If you want to use a default constructor as well as a custom one, you need to explicitly declare and define it. If you don't want to use a default constructor, then pass in arguments to use your custom one.
To declare a default constructor in your .h:
HealthProfile();
And to define it in your .cpp:
HealthProfile::HealthProfile() { }
Or to simply call your existing custom constructor in main:
HealthProfile person(first,last,g,m,d,y,h,w); // AFTER collecting values for these arguments

No Default constructor to run functions in c++?

i want to run the function Run in the main, but am not allowed to create object due to no default constructor. when i try to create the default constructor, i receive the message, 'Error"Game::Game int maxComponents)" provides no initialiser for:'
//Game.h
#pragma once
#include "GameComponent.h"
#include <time.h>
class Game
{
private:
int componentCount;
GameComponent** components;
const int TICKS_1000MS;
public:
Game(){} //this does not work either
Game(int maxComponents){} //this does not work as my default constructor
~Game();
void Add(GameComponent*);
void Run();
};
//Game.cpp
#pragma once
#include "StdAfx.h"
#include "Game.h"
#include <iostream>
#include<time.h>
using namespace std;
void Game::Add(GameComponent*)
{
components= new GameComponent*[componentCount];
}
void Game::Run()
{
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
//cout << timeinfo->tm_hour<< ":" << timeinfo->tm_min << ":" << timeinfo->tm_sec << endl;
for(int n=0;n<componentCount;n++)
{
components[n]->Update(timeinfo);
}
}
Game::~Game()
{
}
//main.cpp
#include "stdafx.h"
#include <iostream>
#include "Game.h"
#include <time.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
Game obj1;
obj1.Run();
system("pause");
return 0;
}
So, how do i create a default constructor here? i've tried to use member initialising too, doesn't work. and copy constructor.
A default constructor is a constructor that takes no arguments. So, you should declare a constructor that looks something like this:
Game() { }
You can keep your other constructor - normal function overloading applies to constructors, so it will use your Game(int) constructor when you specify a single integer argument, and Game() when you specify no arguments.
However, in your case Game contains a const int member (TICKS_1000MS). Since it's const, it's expected to be initialized in the constructor. So you should do something like this:
Game() : TICKS_1000MS(123) { } // replace 123 with whatever the value should be
You need to do that for all constructors.
It's a little silly to have a non-static const member of a class which is always initialized to the same value (as opposed to a value passed in as an argument to the constructor). Consider making it an enum instead:
enum { TICKS_1000MS = 123 };
or, a static const member:
static const int TICKS_1000MS;
and initialize it in Game.cpp:
const int Game::TICKS_1000MS = 123;
As long as you have defined a constructor other than than the default one, the default constructor is not provided anymore so you have to define it manually:
public:
Game() {}
Game(int maxComponents){}
Now you have a default constructor and an overloaded constructor which takes 1 integer parameter.
You will need to create the default parameterless constructor. When you define a constructor you no longer get the default that would have been created behind the scenes.
Game(){}
The default constructor is the one that does not take any parameters, in your case Game(){}.
You do not seem to use the constructor parameter, but if you do, you will have to provide a default value.
Probably you can so something along these lines, you class Game needs to initialize const int in both the constructors:
class Game
{
private:
int componentCount;
GameComponent** components;
const int TICKS_1000MS;
public:
Game(): TICKS_1000MS(100)
{} //this does not work either
Game(int maxComponents): TICKS_1000MS(100)
{} //this does not work as my default constructor
~Game();
void Add(GameComponent*);
void Run();
};
As pointed out by others you need to intialize const data in ctor or initializer list.