0

Let us look at the following class:

ProjectManager.hh

#ifndef INPUT_CPP_FILES_PROJECT_MANAGER_HH #define INPUT_CPP_FILES_PROJECT_MANAGER_HH #include <string> #include "Employee.hh" #include "Programmer.hh" #include "Tester.hh" namespace OrganizationNamespace { class ProjectManager : public Programmer, public Tester { public: ProjectManager():Employee(), Programmer(), Tester() {} explicit ProjectManager(const std::string& id):Employee(id), Programmer(), Tester() {} ProjectManager(std::string&id, std::string &name):Employee(id, name), Programmer(), Tester() {} ProjectManager(std::string &id, std::string &name, std::string &programming_language):Employee(id, name), Programmer(programming_language), Tester() {} ProjectManager(std::string &id, std::string &name, std::string &programming_language, std::string &tool):Programmer(programming_language), Tester(tool),Employee(id, name) {} ProjectManager(ProjectManager const & pm) { this->id_ = pm.id_; this->name_ = pm.name_; this->programming_language_ = pm.programming_language_; this->tool_ = pm.tool_; } void print() const { std::cout << "(" << Employee::id_ << ", " << Employee::name_ << ", " << Programmer::programming_language_ << "," << Tester::tool_ << ")" << std::endl; } }; } #endif //INPUT_CPP_FILES_PROJECT_MANAGER_HH 

main.cpp

#include "Employee.hh" #include "Programmer.hh" #include "ProjectManager.hh" int main() { std::string id = "id"; std::string name = "name"; std::string programming_language = "programming-language"; std::string testing_tool = "testing-tool"; OrganizationNamespace::ProjectManager pm(id, name, programming_language, testing_tool); pm.print(); } 

Output

C:\Users\pc\source\repos\input_cpp_files\cmake-build-debug\input_cpp_files.exe (id, name, ,) Process finished with exit code 0 

As we can see the program is not giving the correct output.

The expected output is:

C:\Users\pc\source\repos\input_cpp_files\cmake-build-debug\input_cpp_files.exe (id, name, programming-language, testing-tool) Process finished with exit code 0 

How can I implement constructors in ProjectManager so that they give the correct output?




Additional Source Code

Employee.hh

#ifndef INPUT_CPP_FILES_EMPLOYEE_HH #define INPUT_CPP_FILES_EMPLOYEE_HH #include <iostream> #include <string> namespace OrganizationNamespace { class Employee { protected: std::string id_; std::string name_; public: Employee() : id_ (""), name_("") {} Employee(const std::string &id) : id_(id), name_("") {} Employee(const std::string &id, const std::string &name) : id_(id), name_(name) {} Employee(Employee const & emp) { this->id_ = emp.id_; this->name_ = emp.name_; } void print() const { std::cout << "(" << id_ << ", " << name_ << ")" << std::endl; } }; } #endif //INPUT_CPP_FILES_EMPLOYEE_HH 

Programmer.hh

#ifndef INPUT_CPP_FILES_PROGRAMMER_HH #define INPUT_CPP_FILES_PROGRAMMER_HH #include "Employee.hh" namespace OrganizationNamespace { class Programmer : public virtual Employee { protected: std::string programming_language_; public: Programmer() : Employee(), programming_language_("") {} Programmer(std::string id) : Employee(id) {} Programmer(std::string id, std::string name) : Employee(id, name) {} Programmer(std::string id, std::string name, std::string programming_language) : Employee(id, name), programming_language_( programming_language) {} void print() const { std::cout << "(" << id_ << ", " << name_ << ", " << programming_language_ << ")" << std::endl; } }; } #endif //INPUT_CPP_FILES_PROGRAMMER_HH 

Tester.hh

#ifndef INPUT_CPP_FILES_TESTER_HH #define INPUT_CPP_FILES_TESTER_HH #include <string> #include "Employee.hh" namespace OrganizationNamespace { class Tester : public virtual Employee { protected: std::string tool_; public: Tester() : Employee(), tool_("") {} Tester(std::string id) : Employee(id) {} Tester(std::string id, std::string name) : Employee(id, name) {} Tester(std::string id, std::string name, std::string tool) : Employee(id, name), tool_(tool) {} void print() const { std::cout << "(" << id_ << ", " << name_ << ", " << tool_ << ")" << std::endl; } }; } #endif //INPUT_CPP_FILES_TESTER_HH 
0

2 Answers 2

2

The problem is that when you call the ProjectManger cosntructor you also call the overloaded cosntructors of Programmer and Tester, the versions you are calling are those which take as parameter one std::string, those constructors change the value of Employee::id_, actually you never changed other values. For fixing the problem you must change

ProjectManager(std::string& id, std::string& name, std::string& programming_language, std::string& tool) : Employee(id, name), Programmer(programming_language), Tester(tool) {} 

in

ProjectManager(std::string& id, std::string& name, std::string& programming_language, std::string& tool) : Employee(id, name), Programmer("","",programming_language), Tester("","",tool) {} 
Sign up to request clarification or add additional context in comments.

4 Comments

It would be better to pass in the known id and name values to the Programmer and Tester classes. This avoids the construction of multiple temporary std::string objects and also avoids the assumption that they will be unused within the constructor.
Yes but this is a virtual inheritence, because of the rules of c++ calling a constructor of a grandson class(ProjectManager) and you didn't specify which granparent class(Employee) constructor the compiler call the default constructor, so you must call the overloaded constructor. But yours is a good point, he could use const std::string & instead of std::string , so the program does not need to cretae useless string
@1201ProgramAlarm, I would request you to kindly post an answer with your proposed solution.
@user366312 I've updated my existing answer with the example code and explanation
1
+100

Your 4-parameter ProjectManager constructor calls the 1-parameter Programmer constructor, which does not set the programming_language_ member. The same for the Tester constructor.

So neither of the member variables for your two classes get anything other than default initialized to empty strings.

The solution is to pass the proper values in the proper parameters, and construct the base classes in the correct order.

namespace OrganizationNamespace { class ProjectManager : public Programmer, public Tester { public: // ... ProjectManager(std::string &id, std::string &name, std::string &programming_language): Employee(id, name), Programmer(id, name, programming_language), Tester() {} ProjectManager(std::string &id, std::string &name, std::string &programming_language, std::string &tool): Employee(id, name), Programmer(id, name, programming_language), Tester(id, name, tool) {} // ... }; 

Even though the id and name parameters won't be used by the Programmer or Tester constructors (because the Employee base class they are passed to is virtual and will be constructed by the most derived object, ProjectManager), we still pass in those values. There are a couple of reasons for that.

  1. Because we already have these string objects, and the constructors take their parameters as references, we avoid the overhead of constructing temporary string objects that will be unused.
  2. The code does not rely on the assumption that the id and name paramaters are unused. It is possible that a future change to the constructors will make use of one or both parameters. By passing in the expected values that can avoid future bugs.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.