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
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.
string
objects, and the constructors take their parameters as references, we avoid the overhead of constructing temporary string objects that will be unused.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.