c++ inheritance/multi-inheritance ambiguous call - c++

Beginner C++ question:
I have a class Person that has protected variables FirstName and LastName:
class Person
{
protected:
int Id;
std::string FirstName;
std::string LastName;
public:
Person();
Person(std::string firstName, std::string lastName);
~Person();
std::string GetPersonInfo() const;
std::string GetFirstName() const;
std::string GetLastName() const;
};
inline std::string Person::GetPersonInfo() const {
return FirstName + " " + LastName;
}
inline std::string Person::GetFirstName() const {
return FirstName;
}
inline std::string Person::GetLastName() const {
return LastName;
}
I have a Teacher class that inherits from Person (and an Adult Class)
class Teacher :
public Person, public Adult
{
private:
int ClassroomID;
public:
Teacher() = default;
~Teacher() = default;
Teacher(std::string firstName, std::string lastName, std::string emailAddress, std::string phoneNumber,
std::vector<Address> teacherAddress, int classroomID);
};
In my main() I have the following:
vector<Teacher> teachers = TeacherRepository.RetrieveTeachers();
for (Teacher teacher : teachers) {
cout << teacher.GetFirstName(); }
When I start to type "teacher." I see "GetFirstName" appear as an option, however; it is throws a compiler error that "Teacher::GetFirstName is ambiguous"
What have I done wrong?
EDIT: Definition for Adult
class Adult :
public Person
{
protected:
std::string Email;
std::string PhoneNumber;
std::vector<Address> address;
public:
Adult() = default;
~Adult() = default;
Adult(std::string emailAddress, std::string phoneNumber, std::vector<Address> address);
Adult(std::string emailAddress, std::string phoneNumber);
};

You have incorrect hierarchy. Teacher inherit from Person and Adult at the same time and Adult inherit Person too. What do you want compiler call when you write Teacher::GetFirstName? Maybe Person::GetFirstName or Adult::Person::GetFirstName. Moreover you will have two exemplars of Person's variables.
Decisions:
virtual inheritance:
class Adult : virtual public Person {...};
class Teacher : virtual public Person, public Adult {...};
more here
teacher's basic class must be Adult only:
class Teacher : public Adult {...};
As bad option: you can to indicate explicit which certainly method you want to call:
`Teacher t = ...;
t.Adult::GetFirstName();`
Bonus: Don't pass arguments by value, in your case will be better pass arguments as constant reference.
`Person(const std::string& firstName, const std::string& lastName);`
Instead
`Person(std::string firstName, std::string lastName);`

There are multiple issues in your previous design. The direct issue that causes the compilation error is that your Teacher is inherited from both Adult and Person class. Since Adult is also a subclass of Person, both of those classes have GetLastName() method, so the compiler cannot tell which one to call.
More importantly, you should manage your hierarchy in a more correct and clear way. Semantically, an adult should also be a person and a teacher is supposed to be an adult. So why not just inherit Teacher from Adult only and make your hierarchy a linear list in your design?
Moreover, if you want complete information for your base classes, you should initialize your base class objects first in your derived class object. Use C++ initialization list to complete this.
class Person
{
protected:
int Id;
std::string FirstName;
std::string LastName;
public:
Person() = default;
Person(std::string firstName, std::string lastName) : FirstName(firstName), LastName(lastName) {}
~Person() = default;
std::string GetPersonInfo() const;
std::string GetFirstName() const;
std::string GetLastName() const;
};
inline std::string Person::GetPersonInfo() const {
return FirstName + " " + LastName;
}
inline std::string Person::GetFirstName() const {
return FirstName;
}
inline std::string Person::GetLastName() const {
return LastName;
}
class Adult : public Person
{
protected:
std::string Email;
std::string PhoneNumber;
std::vector<std::string> Address;
public:
Adult() = default;
~Adult() = default;
Adult(std::string firstName, std::string lastName, std::string emailAddress, std::string phoneNumber, std::vector<std::string> address)
: Person(firstName, lastName), Email(emailAddress), PhoneNumber(phoneNumber), Address(address) {};
Adult(std::string firstName, std::string lastName, std::string emailAddress, std::string phoneNumber)
: Person(firstName, lastName), Email(emailAddress), PhoneNumber(phoneNumber) {};
};
class Teacher : public Adult
{
private:
int ClassroomID;
public:
Teacher() = default;
~Teacher() = default;
Teacher(std::string firstName, std::string lastName, std::string emailAddress, std::string phoneNumber,
std::vector<std::string> teacherAddress, int classroomID)
: Adult(firstName, lastName, emailAddress, phoneNumber, teacherAddress), ClassroomID(classroomID) {}
};
int main(void) {
Teacher teacher("ExampleFirstName", "ExampleLastName", "example#email.com", "100-1001000", {"example address"}, 1);
cout << teacher.GetLastName() << endl;
return 0;
}

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 } {}

can someone please explain what is wrong in this c++ code and provide a solution

I have declared a class Products and another class CD the class CD is inheriting the class Products.
Now I have declared an constructor to update the value of the. and I am getting an error
#include <iostream>
#include <string>
class Products
{
private:
std::string name;
std::string type;
double price;
public:
virtual std::string getname();
virtual double getprice();
virtual void show();
std::string gettype()
{
return type;
}
};
class CD: public Products
{
private:
std::string artist;
std::string studio;
public:
CD(std::string sname,double sprice,std::string sartist,std::string sstudio)
{
this->type = "CD";
this->name = sname ;
this->price = sprice;
this->artist = sartist;
this->studio = sstudio;
}
void show()
{
std::cout<<"\nName of the CD:\t"<<this->name;
std::cout<<"\nArtist of the CD:\t"<<this->artist;
std::cout<<"\nStudio of the CD:\t"<<this->studio;
std::cout<<"\nPrice of the cd:\t"<<this->price;
}
};
int main()
{
CD obj("Oceans",49,"somesinger","somestudio");
}
ERROR :
In constructor 'CD::CD(std::string, double, std::string)';
'std::string Products::type' is private within this context
this->type="CD";
'std::string Products::name' is private within this context
this->name=sname;
'double Products::price' is private within this context
this->price= sprice;
Basically it is not giving error for the private data members of the CD class but just the data members that are being inherited from Products Class
#include <iostream>
#include <string>
class Products
{
private:
std::string m_name;
std::string m_type;
double m_price;
public:
// No need for your setters/getters to be virtual
// if the derived class won't override anything or not
const std::string& getType() const { return m_type; }
const std::string& getName() const { return m_name; }
double getPrice() const { return m_price; }
void setType(const std::string& new_type) { m_type = new_type; }
void setName(const std::string& new_name) { m_name = new_name; }
void setPrice(double new_price) { m_price = new_price; }
// Force derived class to override function
virtual void show() = 0;
};
class CD: public Products
{
private:
std::string artist;
std::string studio;
public:
CD(std::string sname,double sprice,std::string sartist,std::string sstudio)
{
this->setType("CD");
this->setName(sname) ;
this->setPrice(sprice);
this->artist = sartist;
this->studio = sstudio;
}
void show()
{
std::cout<<"\nName of the CD:\t"<<this->getName();
std::cout<<"\nArtist of the CD:\t"<<this->artist;
std::cout<<"\nStudio of the CD:\t"<<this->studio;
std::cout<<"\nPrice of the cd:\t"<<this->getPrice();
}
};
int main()
{
CD obj("Oceans",49,"somesinger","somestudio");
obj.show();
}
I want you to understand some changes here. First the removal of virtual keyword. In your case the setters/getters had no need to be virtual, as they were not being overriden or didn't have a need to be based on the current example. Second, the setters/getters are setup to access the private members accordingly. We now use these functions within class CD. Also we changed the function show() to be pure virtual notice the = 0 at the end. I added a comment saying this forces derived classes to override the function. Lastly, your main wasn't doing anything so I added a obj.show() to actually print something.
In this solution, I've added a constructor for Products, and CD's constructor calls it to initialize the members that are private to Products.
I removed the virtual on getName and getPrice since these features don't change other products.
show remains virtual, and I split it into a piece in Products and a piece in CD so they each display their respective fields. This separates the printing according to where the variables are, so for example, another class derived from Products wouldn't have to reimplement printing of name and price.
#include <iostream>
#include <string>
class Products
{
private:
std::string name;
std::string type;
double price;
public:
std::string getname(); // Does not need to be virtual, as it's not overriden
double getprice(); // Also does not need to be virtual
virtual void show() const {
std::cout<<"\nName of the " << type << ":\t"<<this->name;
std::cout<<"\nPrice of the " << type << ":\t"<<this->price;
};
Products (const std::string &stype, double sprice, const std::string &sname)
: name (sname), type (stype), price (sprice) {
}
std::string gettype() const
{
return type;
}
};
class CD: public Products
{
private:
std::string artist;
std::string studio;
public:
CD(const std::string &sname,double sprice, const std::string &sartist, const std::string &sstudio)
: Products ("CD", sprice, sname)
{
artist = sartist;
studio = sstudio;
}
void show() const override
{
Products::show(); // Call parent show() to show the basics
std::cout<<"\nArtist of the " << gettype() << ":\t"<<this->artist;
std::cout<<"\nStudio of the " << gettype() << ":\t"<<this->studio;
}
};
int main()
{
Products shoe ("Shoe", 3.49, "Nike runner");
shoe.show();
CD obj("Oceans",49,"somesinger","somestudio");
obj.show();
}

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

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.

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) {

List iterator outside range

I have a problem with the STL list class. I have a base class called Contact, and three derived classes, Friend, Colleague and Acquaintance. Each instance of the derived classes has certain fields which I modify in the fill*Class*Details() function. The problem is that when it reaches the push_back line, my program gives me an error saying list insert iterator outside range. What can that be from?
void Agenda::pushContact(string line, string temp)//function that adds a contact of type temp, containing the fields from line to the list
{
Contact *c;
if(temp=="friend") //the contact to add is of type friend
{
c = new Friend();
fillFriendDetails(c,line);//the details of Friend c will be filled
}
else if(temp=="colleague")
{
c = new Colleague();
fillColleagueDetails(c,line);//the details of Colleague c will be filled
}
else if(temp=="acquaintance")
{
c = new Acquaintance();
fillAcquaintanceDetails(c,line);//the details of Acquaintance c will be filled
}
contactList.push_back(c);
}
Also, the contactList is defined as list <Contact*> contactList;.
Edit: This is how the Contact class (+derived classes) are defined:
class Contact
{
public:
string getFullName() { string fullName;fullName.append(firstName); fullName.append(" ");fullName.append(lastName); return fullName;}
public:
void setFullName(string newFirstName, string newLastName) { firstName = newFirstName; lastName = newLastName;}
public:
string getFirstName() { return firstName;}
public:
void setFirstName(string newFirstName) {firstName = newFirstName;}
public:
string getLastName(){return lastName;}
public:
void setLastName(string newLastName){lastName = newLastName;}
public:
string getPhoneNo(){return phoneNo;}
public:
void setPhoneNo(string newPhoneNo) {phoneNo = newPhoneNo;}
public:
void setType(string newType){type=newType;}
public:
string getType(){return type;}
private:
string firstName;
string lastName;
string phoneNo;
string type;
//SubClass setters and getters
public:
virtual void setDateOfBirth(string birth) {}
virtual string getDateOfBirth() {return 0;}
virtual void setCity (string newCity) {}
virtual string getCity() {return 0;}
virtual void setFaculty (string newFaculty) {}
virtual string getFaculty() {return 0;}
virtual void setGroup (string newGroup) {}
virtual string getGroup() {return 0;}
virtual void setJob (string newJob) {}
virtual string getJob () {return 0;}
};
class Friend : public Contact
{
public:
void setDateOfBirth(string birth) {dateOfBirth=birth;}
public:
string getDateOfBirth() {return dateOfBirth;}
public:
void setCity (string newCity){city=newCity;}
public:
string getCity(){return city;}
private:
string dateOfBirth;
string city; //current city of residence
};
class Colleague : public Contact
{
public:
void setFaculty (string newFaculty){faculty = newFaculty;}
public:
string getFaculty(){return faculty;}
public:
void setGroup (string newGroup){group = newGroup;}
public:
string getGroup(){return group;}
private:
string faculty;
string group;
};
class Acquaintance : public Contact
{
public:
void setJob (string newJob){job=newJob;}
public:
string getJob (){return job;}
private:
string job;
};
It looks like the list is being mismanaged at a different point in the code, because the error implies end is incorrect. Most likely either the list is deleted/out of scope or some incorrect erases were performed on the list elements (say using invalid iterators).