Diamond problem with Multiple inheritance C++ - c++

I have a homework task with a given main.cpp code which is not allowed to be changed. According to that main.cpp and simple input and output(which is down below) example I must to finish the program.
My tries are: I'm trying to create 4 classes, class Person; class Worker; class Student; class InService; in my main function through instantiating an object of InService class I pass 4 parameters (name, sex, studentNo, workerNo); and with help of pointer of type of Base class, have the desired output. The error it shows is:
[Error] no unique final overrider for 'virtual std::string Person::getName()' in 'InService'
[Error] no unique final overrider for 'virtual int Person::getSex()' in 'InService'
I've tried to use virtual inheritance for that, but I can't really figure out how to solve this problem. I did some research on virtual inheritance, and referenced to other experts answers, but still getting confused with whole OOP stuff.
//Inservice.h
#include<string>
using namespace std;
class Person{
public:
Person();
~Person();
string name;
int sex;
virtual string getName() = 0;
virtual int getSex() = 0;
};
///////////////////////////////////////////////////
class Student:virtual public Person{
public:
Student();
~Student();
string sno;
virtual string getName() {
return name;
}
virtual int getSex(){
return sex;
}
string getSno(){
return sno;
}
};
//////////////////////////////////////////////////
class Worker:virtual public Person{
public:
Worker();
~Worker();
string wno;
virtual std::string getName(){
return name;
}
virtual int getSex(){
return sex;
}
string getWno(){
return wno;
}
};
///////////////////////////////////////////////////////
class InService: public Student, public Worker{
public:
InService(string _name, int _sex, string _sno, string _wno){
Person::name = _name;
Person::sex - _sex;
Worker::wno = _wno;
Student::sno = _sno;
}
};
///////////////////////////////////////////////////////
//main.cpp
#include <iostream>
#include "inservice.h"
using namespace std;
int main() {
string name, sno, wno;
int sex;
cin >> name;
cin >> sex;
cin >> sno;
cin >> wno;
InService is(name, sex, sno, wno);
Person* p = &is;
Student* s = &is;
Worker* w = &is;
cout << p->getName() << endl;
cout << p->getSex() << endl;
cout << s->getName() << endl;
cout << s->getSex() << endl;
cout << s->getSno() << endl;
cout << w->getName() << endl;
cout << w->getSex() << endl;
cout << w->getWno() << endl;
return 0;
}
Suppose my input is:
Jack
1 //1-for male; 0 -for female
12345678 //studentNo
87654321 //workerNo
I expect the output to be:
Jack
1
12345678
Jack
1
87654321

InService(string _name, int _sex, string _sno, string _wno){
Person::name = _name;
Person::sex - _sex;
Worker::wno = _wno;
Student::sno = _sno;
}
There's a typo there, Person::sex - _sex; should be Person::sex = _sex;
Also you can remove name and sex virtual function and have it just a standard function in Person, since it's exactly the same for all classes that derive from it. That will remove the ambiguity of which getName and getSex function that InService class virtual table needs to point to.

Related

Inheritance in C++, how to initialize member variables in base class from derived class

i just opened up c++ today for the first time almost, and i tried doing some inheritance.
I have a class called Person and three classes that derive from Person called:
Retiree,
Adult,
Child.
The console asks for your age and in the case that you type 30 into the console i want to make a new adult object, and here i want to pass in the parameters: age, name and discount.
In java i would just call the constructor in the child class, as it has the super(a, b, c) in it. But when i try to do it here, it won't work, and i can't seem to figure out why.
Down below is two cpp files for Person and Adult showing their constructors and lastly the Main.cpp
I get this error when i try to create the object "Unhandled exception at 0x759EA842 in LearnCPP.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x00AFF514."
Person.h
#pragma once
#include <String>
#include "BudgetAccount.h"
class Person
{
private:
public:
Person(int32_t age, std::string name);
int32_t getAge();
void setAge(int32_t age);
std::string getName();
void setName(std::string name);
protected:
int32_t age;
std::string name;
};
Person.cpp
#include "Person.h"
#include <String>
Person::Person(int32_t age, std::string name)
{
this->age = age;
this->name = name;
}
int32_t Person::getAge()
{
return age;
}
void Person::setAge(int32_t age)
{
this->age = age;
}
std::string Person::getName()
{
return name;
}
void Person::setName(std::string name)
{
this->name = name;
}
Adult.h
#pragma once
#include "Person.h"
class Adult : public Person
{
private:
double discount;
public:
Adult(double discount);
};
Adult.cpp
#include "Adult.h"
Adult::Adult(double discount) : Person(age, name)
{
this->discount = discount;
}
Main.cpp
#include <iostream>
#include "Person.h"
#include "Adult.h"
int main()
{
std::cout << "Hello Customer" << std::endl;
std::cout << "Down below you see a list of cities" << std::endl;
std::cout << "Please enter your name" << std::endl;
//Cin
std::string name;
std::cin >> name;
std::cout << "Please enter your age" << std::endl;
std::int32_t age;
std::cin >> age;
//Check if the entered age is child, adult or retiree
Adult user(50.0);
std::cout << "Please select which city you want to travel to" << std::endl;
return 0;
}
I think this is your problem:
Adult::Adult(double discount) : Person(age, name)
{
this->discount = discount;
}
You haven't passed in an age or name to this constructor, so it's using them from the parent class -- whose constructor hasn't been called yet.
As previously mentioned, you haven't passed the value for name and age.
One solution to this is that you can change the constructor to take in the values for age and name.
Another solution is that you can define default constructor. You can also set default values in the parameterised constructor.
Person::Person(int32_t age = 0, std::string name = ""){
this->age = age;
this->name = name; }

why is the same objects method called twice?

I've been doing c++ self study after taking two semesters of Java.
Below is a simple program which builds fine, but when I run it I get gradeBook2s displayInfo() method called twice. I'm sure its something basic I am missing, but any ideas why?
//GradeBook.h
#include<string>
#include<iostream>
using std::cout;
using std::endl;
using std::string;
string courseName;
int courseGrade;
class GradeBook {
public:
GradeBook(string name, int grade) {
setCourseName(name);
setCourseGrade(grade);
}
public:
void setCourseName(string name) {
courseName = name;
}
public:
string getCourseName() {
return courseName;
}
public:
void setCourseGrade(int score) {
courseGrade = score;
}
public:
int getCourseGrade() {
return courseGrade;
}
public:
void displayInfo(){
cout << "Course Name: " << getCourseName()
<< "Course grade: " << getCourseGrade()
<< endl;
}
};
//main.cpp
#include<iostream>
#include "GradeBook.h"
int main() {
GradeBook gradeBook1("Calculus 2", 90);
GradeBook gradeBook2("Chemistry", 80);
gradeBook1.displayInfo();
system("pause");
gradeBook2.displayInfo();
system("pause");
}
The problem that you have is that you are saving the variables courseName and courseGrade as global variables. Because of this, you are overwriting the previous class instance's data with the current, in this case, Chemistry. What you need to do is move the declaration of courseName and courseGrade inside the accessor private inside the class, like this:
class GradeBook {
private:
string courseName;
int courseGrade;
public:
//put your functions here
}
The locations where the code stores values is global, so all instances will appear the same.

Derived Class C++ [duplicate]

This question already has answers here:
What is this weird colon-member (" : ") syntax in the constructor?
(14 answers)
Closed 6 years ago.
I know that it can be a stupid but I even don't know how to name this question. I'm non native English. I learn C++ from a book and there is a program which shows name and pay rate of employee (base class) and Manager (derived class) with added bool variable salaried. Here is the source code:
//base class
class Employee {
private:
string name;
double pay;
public:
Employee() {
name = "";
pay = 0;
}
Employee(string empName, double payRate) {
name = empName;
pay = payRate;
}
string getName() const {
return name;
}
void setName(string empName) {
name = empName;
}
double getPay() const {
return pay;
}
void setPay(double payRate) {
pay = payRate;
}
string toString() {
stringstream stm;
stm << name << ": " << pay;
return stm.str();
}
};
//derived class
class Manager : public Employee {
private:
bool salaried;
public:
Manager(string name, double payRate, bool isSalaried)
:Employee(name, payRate)
{
salaried = isSalaried;
}
bool getSalaried() {
return salaried;
}
};
int main()
{
Employee emp1("Mary Smith", 15.00);
cout << "Employee name: " << emp1.getName() << endl;
cout << "Employee pay rate: " << emp1.getPay() << endl;
Manager emp2("Bob Brown", 1500, true);
cout << "Employee name: " << emp2.getName() << endl;
cout << "Employee pay rate: " << emp2.getPay() << endl;
cout << "Is Salaried: " << emp2.getSalaried() << endl;
return 0;
}
Can someone explain me why this part
:Employee(name, payRate)
must be added to code to work properly?
The part
:Employee(name, payRate)
you mention is used to call the constructor
Employee(string empName, double payRate)
of the base class Employee before executing the body of the constructor
Manager(string name, double payRate, bool isSalaried)
of the derived class Manager.
It calls the base class's (Employee) constructor and passes the name and payRate to it because they are members of Employee.
:Employee(name, payRate)
is the initialisation of the base class that class Manager inherits.
In fact without this line the code should compile fine(because you have a default constructor for Employee), but the fields inherited from Employee will not get properly initialized in emp2. What this portion of the code does is to call the constructor of Employee to initialize the fields inherited from that class.
What come after the colon on the constructor called initialization list and in your case it just initiate the base class with the suitable constructor
The code can work properly even without the constructor(i.e..you can use the default constructor to accept the variables and implement two methods for filling the name and pay.)
class Employee {
private:
string name;
string temp_name;
double temp_pay;
double pay;
public:
Employee() {
name = temp_name;
pay = temp_pay;
}
void getTempname(string tem){temp_name = tem;}
void getTemppay(double py){ temp_pay = pay;}
};

What does "Invalid operands to binary expression (ostream and void)" mean, and how can it be fixed?

I'm encountering an error that says:
Invalid operands to binary expression ('ostream' (aka 'basic_ostream') and 'void')
I understand there are some questions related to this error posted on StackOverflow but I need some help and explanations regarding this specific context on what this error means.
In the main() function, I create a student object called s1. The error happens in main() where I'm trying to get the results of his GPA using a method of the Student class called getResults(double gpa).
#include <iostream>
using namespace std;
class Human{
protected: string name;
protected: int age;
public: Human(){
name = "Unknown";
age = 5;
}
public:
Human(string name, int age){
this->name = name;
this->age = age;
}
string getName(){
return name;
}
int getAge(){
return age;
}
void setName(string name){
this->name = name;
}
void setAge(int age){
this->age = age;
}
};
class Student: public Human{
protected: string school;
protected: double gpa;
public:
Student(string name, int age, string school, double gpa) : Human(name, age){
this->school = school;
this->gpa = gpa;
}
double getGPA(){
return gpa;
}
string getSchool(){
return school;
}
void setGPA(double gpa){
this->gpa = gpa;
}
void setSchool(string school){
this->school = school;
}
void getResult(double gpa){
if (gpa < 3.0) {
cout << "You did well!";
} else {
cout << "Try harder next time";
}
}
};
int main() {
Student s1 ("John", 23, 'm', "University of Chicago", 3.4);
double s1GPA = s1.getGPA();
cout << s1.getResult(s1GPA) << endl;
return 0;
}
Currently, your getResults function has a void return type, which means it doesn't actually return anything. Because of this, do not try to cout the result of this function in your main.
Consider the following edit:
// Your result is printed within this function
s1.getResult(s1GPA);
// Print a new line if you wish
cout << endl;
Also, since your getResults doesn't really get anything, I'd suggest changing the name to something like printResults.
Note
Notice how in your getResult it doesn't return anything because it's a void. In this function, you're just outputting text to the console with cout:
// Notice that this function doesn't actually return anything
void getResult(double gpa){
if (gpa < 3.0) {
// Output this message to console
cout << "You did well!";
} else {
// Output this message to console
cout << "Try harder next time";
}
}
When you have the statement in your main, it's trying to cout nothing because getResult is a void:
cout << s1.getResult(s1GPA) << endl;
// ^^^^^^^^^^^^^^^^^^^
// This doesn't return anything for cout to output.
That is why you only need to call getResult instead of trying to cout it.

Getting the linker error for following c++ code [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 7 years ago.
I recently started learning object oriented programming..for the following code, I am getting the linker error !!
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class person{
public:
string name;
person();
person(string n){
name = n ;
}
void setName(string k){
name = k;
}
string getName(){
return name;
}
};
class student : public person {
public:
string major;
void setMajor(string m){
major = m;
}
string getMajor(){
return major;
}
};
class faculty : public person{
public:
string department;
faculty(string dept){
department = dept;
}
void setDepartment(string depart){
department = depart;
}
string getDepartment(){
return department;
}
};
int main() {
student s;
s.setName("james");
s.setMajor("computer science");
string p = s.getName();
string p2 = s.getMajor();
cout << "student name and mjor is :" << p << p2 << endl;
faculty f("nanotech");
f.setName("chris");
f.setDepartment("electrical");
string f1 = f.getName();
string f2 = f.getDepartment();
cout << "facult name and department :" << f1 << f2 << endl;
return 0;
}
The following error i am getting , when i try to compile the code.
/tmp/ccYHu2de.o: In function `faculty::faculty(std::string)':
person.cpp:(.text._ZN7facultyC2ESs[_ZN7facultyC5ESs]+0x19): undefined reference to `person::person()'
/tmp/ccYHu2de.o: In function `student::student()':
person.cpp:(.text._ZN7studentC2Ev[_ZN7studentC5Ev]+0x15): undefined reference to `person::person()'
collect2: error: ld returned 1 exit status
In your class person you have a constructor that is declared but is not defined. The compiler let you compile the class but then the linker looks for an implementation (which is called forward declaration):
class person{
public:
string name;
person(); //constructor only declared
person(string n){
name = n ;
}
.....
};
The problem is that you inherit from person in your student and faculty, you use the default constructor but you never implement it. Try to add an implementation and the linker error will disappear:
class person{
public:
string name;
person(){} //constructor implemented
person(string n){
name = n ;
}
.....
};
The Problem is that you need to implement the constructor of the person class, Try this code: http://ideone.com/NfXP7R
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class person{
public:
string name;
person() {
}
person(string n){
name = n ;
}
void setName(string k){
name = k;
}
string getName(){
return name;
}
};
class student : public person {
public:
string major;
void setMajor(string m){
major = m;
}
string getMajor(){
return major;
}
};
class faculty : public person{
public:
string department;
faculty(string dept){
department = dept;
}
void setDepartment(string depart){
department = depart;
}
string getDepartment(){
return department;
}
};
int main() {
student s;
s.setName("james");
s.setMajor("computer science");
string p = s.getName();
string p2 = s.getMajor();
cout << "student name and mjor is :" << p << p2 << endl;
faculty f("nanotech");
f.setName("chris");
f.setDepartment("electrical");
string f1 = f.getName();
string f2 = f.getDepartment();
cout << "facult name and department :" << f1 << f2 << endl;
return 0;
}