C++ - Unable to inherit from base class | Gives empty values - c++

I guess I am doing something wrong here in the below code. I want to inherit the methods of class Person in class Employee.
#include<bits/stdc++.h>
using namespace std;
class Person{
private:
string name;
int age;
public:
Person(string name, int age){ //Base parameterized constructor
name = name;
age = age;
}
void getName(){
cout<<"Name: "<<name<<endl;
}
void getAge(){
cout<<"Age: "<<age<<endl;
}
};
class Employee: public Person{ //Default inheritance type is private
private:
int employeeID;
public:
Employee(string name, int age, int id) : Person(name, age){ //Derived parameterized constructor
employeeID = id;
}
void getEmployeeDetails(){
getName();
getAge();
cout<<"Employee ID: "<<employeeID<<endl;
}
};
int main(){
Employee* e = new Employee("John", 24, 14298);
e->getEmployeeDetails();
return 0;
}
I am getting the below output:
Name:
Age: 0
Employee ID: 14298
Please let me know what am I missing here. Any help would be appreciated!

The issue is not with inheritance, but with the fact that Person never initializes any of its fields.
This code:
Person(string name, int age){ //Base parameterized constructor
name = name;
age = age;
}
assigns local variable name to itself and same with age, because parameters shadow class member names. Member objects with the same name are never initialized.
Three solutions possible (listed in subjective order in which I prefer them):
Use member initializer list to initialize your members:
Person(string name, int age) : name{name}, age{age}
{
}
Use different names
Person(string providedName, int providedAge)
{
name = providedName;
age = providedAge;
}
Use this to disambiguate objects
Person(string name, int age){ //Base parameterized constructor
this->name = name;
this->age = age;
}

Nothing to do with inheritance, the code would have been wrong anyway.
This
Person(string name, int age){ //Base parameterized constructor
name = name;
age = age;
}
should be this
Person(string n, int a){
name = n;
age = a;
}
Because your constructor parameter declaration names are the same as your member variables, the member variables are hidden and you were just assigning the parameters to themselves.
A better way to write the same code is to use an initialiser list
Person(string name, int age) : name(name), age(age)
}
Initialiser lists have a couple of advantages, one of them is that there's no ambiguity, you can have the parameter names the same as the member variable names. The other (more important) is that in general, initialisation is more efficient than assignment.

Related

Compilation error on diamond problem(inheritance)

Why does the code below throw the following compilation error on msvc ?
No default constructor exists for class 'Person'
If I don't create a default constructor in the class Person, then should I delete the constructor of Employee and Student that takes only one argument and call Employee(name,age,grade) and Student(name,age,cl) from ctor of Manager although the Base class constructor is never going to get called from Employee and Student class?
#include<iostream>
#define endl '\n'
using std::cout;
class Person {
std::string mname;
int mage;
public:
//Person() = default;
Person(const std::string& name, int age) :mname{ name }, mage{ age }{}
};
class Employee :virtual public Person {
int msalary;
public:
Employee(const std::string& name, int age, int sal) :Person{ name,age }, msalary{ sal }{}
Employee(int sal): msalary { sal }{}
};
class Student : virtual public Person {
int mclass;
public:
Student(const std::string& name, int age, int cls) :Person{ name,age }, mclass{ cls }{}
Student(int cls) :mclass{ cls } {}
};
class Manager :public Student, Employee {
private:
public:
Manager(const std::string& name,int age, int salary,int cl) :Person{name,age}, Student{cl}, Employee{salary} {}
};
int main() {
Manager manager{ "lorem",40,10000 ,10};
return 0;
}
Why does the above code throws compilation error
The problem is that before entering the body of the ctor Employee::Employee(int), the default ctor Person::Person() of Person will be used but the compiler will not synthesize the default ctor Person::Person() as the parameterized ctor Person::Person(const std::string&, int) is present.
The error can be reproduced by just the following example:
class Person {
std::string mname;
int mage;
public:
//Person() = default;
Person(const std::string& name, int age) :mname{ name }, mage{ age }{}
};
class Employee :virtual public Person {
int msalary;
public:
Employee(const std::string& name, int age, int sal) :Person{ name,age }, msalary{ sal }{}
//--------------------v--------------------->here Person::Person() is called implicitly
Employee(int sal): msalary { sal }{}
};
Demo error
The cause of the problem:
Both Employee and Student have constructors that do not call the only available constructor of the base class Person (requireing name and age parameters). Therefore the compiler will attempt to use a default constuctor fo the base class which is not available.
You can handle it the following way:
Decide what will be the default name and age for a Person derived class like Employee, Student.
Use the defaults to construct the base, e.g.:
static inline const std::string DEFAULT_NAME = "<default_name>";
static inline const int DEFAULT_AGE = 20;
Employee(int sal) : Person(DEFAULT_NAME, DEFAULT_AGE), msalary{ sal } {}

No definition in cpp composition when I define in function

#include <iostream>
using namespace std;
class Date{
private:
int day;
int month;
int year;
public:
Date(int dy,int mt,int yr){
day=dy;
month=mt;
year=yr;
}
void showDate(){
cout<<day<<"/"<<month<<"/"<<year<<endl;
}
};
class Human{
private:
string name;
Date birthDay;
public:
Human(string nm,Date bd):name(nm),birthDay(bd){};
showHumanInfo(){
cout<<"The person named : "<<name<<" was born : ";
birthDay.showDate();
}
};
int main()
{
Date birthday(1,2,1995);
Human h1("alek",birthday);
h1.showHumanInfo();
return 0;
}
This works, but why it doesn't work when I do the following?
#include <iostream>
using namespace std;
class Date{
private:
int day;
int month;
int year;
public:
Date(int dy,int mt,int yr){
day=dy;
month=mt;
year=yr;
}
void showDate(){
cout<<day<<"/"<<month<<"/"<<year<<endl;
}
};
class Human{
private:
string name;
Date birthDay;
public:
Human(string nm,Date bd){
name = nm;
birthDay = bd;
}
showHumanInfo(){
cout<<"The person named : "<<name<<" was born : ";
birthDay.showDate();
}
};
int main()
{
Date birthday(1,2,1995);
Human h1("alek",birthday);
h1.showHumanInfo();
return 0;
}
I have problem like that. Why can't I use date class in a human class?
When I change human public class like that
public:
human(){
// ...
}
It not working it thing is the same think but not adding date class in human class.
In the definition of a constructor, all member variables must be initialized before the body of the constructor is executed. Since Date doesn't have a default constructor, there is no way to initialize it
Human(string nm, Date bd)
{ // birthDay must be initialized before this point
// ...
birthDay = bd; // this is assignment, which is too late
}
The fix is to either give Date a default constructor, if that makes sense, or to initialize birthDay in a member initializer list, as you did in the first example code.
I think problems comes from "birthday = bd;"
It has been a while since the last time I coded in C++ but if I am not wrong, using constructor initialiser and using equal operator are not the same.
You should override "=" operator to use it with your object.
About his

Calling superclass function inheritance c++

In my C++ file, when I run it visual studio, my output is not what I thought it was be an I don't know where I messed up. Basically I have a Person and a Student class, and the student class inherits from the Person class, and when the student obj is created, it calls the Person class to initialize common variables.
class Person {
public:
Person() {
}
Person(string _name, int _age) {
name = _name;
age = _age;
}
void say_stuff() {
cout << "I am a person. " << name << age << endl;
}
private:
string name;
int age;
};
class Student : public Person {
public:
Student(string _name, int _age, int _id, string _school) {
Person(_name, _age);
id = _id;
school = _school;
}
private:
string name;
int age;
int id;
string school;
};
int main() {
Student s1("john", 20, 123, "AAAA");
s1.say_stuff();
system("pause");
return 0;
}
My output is I am a person. -858993460
Why is this?
The way you invoke the constructor of the super class is wrong. This is how you should do it:
Student(string _name, int _age, int _id, string _school) : Person(_name, _age) {
id = _id;
school = _school;
}
Note that, When you put Person(_name, _age); inside the body, it has no effect but to construct a temporary Person object. On the other hand, the correct way above references the "embedded" Person to be constructed with these parameters.
Your Student constructor's syntax is wrong, for constructing it's superclass. It should be:
Student(string _name, int _age, int _id, string _school)
: Person(_name, _age) {

Inheritance and Multiple Constructor

Okay so I have this person class.
#ifndef PERSON_H
#define PERSON_H
#include<string>
using namespace std;
class Person
{
protected:
string name;
int age;
public:
Person();
Person(string newname, int newage);
void SetName(string n);
void SetAGe(int a);
string GetName();
int GetAge();
};
#endif
And the following person.cpp file.
#include "Person.h"
Person::Person(string newname, int newage){
name = newname;
age = newage;
}
And this Employee.h and .cpp file
#ifndef EMPLOYEE_H
#define EMPLOYEE_H
#include<string>
#include "Person.h"
using namespace std;
class Employee : public Person
{
protected:
float payrate;
public:
//Member functions
Employee() : Person(){ payrate = 10; }; //Constructor
Employee(float newpay); //Constructor
void SetPayrate(float p);
float GetPayrate{ return p; }
#endif
Here's the cpp I had forgotten
#include "Employee.h"
Employee::Employee(float pay) : Person()
{
payrate = pay;
}
And this is supposed to be able to use this line of code
Employee b("Jane", 21, 12.38);
To create an employee with the name Jane, age 21, and payrate of 12.38, but it says that there is no method of the matching arguments. Am I missing something basic? Thanks.
Your Employee class has two explicitly declared constructors:
Employee() : Person(){ payrate = 10; }; //Constructor
Employee(float newpay); //Constructor
The compiler gives you a copy constructor. Given these, you can construct an Employee using one of the three constructors only.
Employee e1; // OK. Uses the first constructor.
Employee e2(2.4f); // OK. Uses the second constructor.
Employee e3(e2); // OK. Uses the copy constructor
Employee e4 = e2; // OK. Uses the copy constructor
Any other way of constructing an Employee is not allowed. If you want to construct an Employee using
Employee e5("Jane", 21, 21.38);
you have declare a constructor that can accept those as arguments. E.g.
Employee(std::string const& name, int age, float payrate);
Constructors are not inherited, and the compiler won't create new constructors like this for you.
You didn't write a constructor Employee(string, int, float), so you can't call it.
If you add one, then you can:
// in the Employee class
Employee(string newname, int newage, float newpayrate)
: Person(newname, newage)
{
payrate = newpayrate;
}
You can, of course, put it all on one line if you want.
You could also put the definition in Employee.cpp, if you want. (Either way works.)

Struct Initialization Arguments

I have a struct, player, which is as follows:
struct player {
string name;
int rating;
};
I'd like to modify it such that I declare the struct with two arguments:
player(string, int)
it assigns the struct's contents with those values.
you would use the constructor, like so:
struct player {
player(const string& pName, const int& pRating) :
name(pName), rating(pRating) {} // << initialize your members
// in the initialization list
string name;
int rating;
};
Aside from giving your type a constructor, because as-shown it is an aggregate type, you can simply use aggregate initialization:
player p = { "name", 42 };
Although (as has been pointed out), you can simply add a constructor:
struct player() {
string name;
int rating;
player(string Name, int Rating) {
name = Name; rating = Rating;
}
};
Is there some reason you don't want to make it a class?
class player() {
public:
string name;
int rating;
player(string Name, int Rating) {
name = Name; rating = Rating;
}
};
You are allowed to declare a constructor for your player struct:
struct player {
string name;
int rating;
player(string n, int r) :
name(n),
rating(r)
{
}
};
In C++ one of the few differences between classes and structs is that class members default to private, while struct members default to public.