如何通过重用 base-class 构造函数来实现 derived-class 构造函数?
How can I implement derived-class constructors by reusing base-class constructors?
让我们看看下面的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();
}
输出
C:\Users\pc\source\repos\input_cpp_files\cmake-build-debug\input_cpp_files.exe
(id, name, ,)
Process finished with exit code 0
正如我们所见,程序没有给出正确的输出。
预期输出为:
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
如何在 ProjectManager
中实现构造函数以便它们提供正确的输出?
附加源代码
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
您的 4 参数 ProjectManager
构造函数调用 1 参数 Programmer
构造函数,它不设置 programming_language_
成员。 Tester
构造函数也是如此。
所以你的两个 class 的成员变量都没有得到除默认初始化为空字符串之外的任何东西。
解决方案是在正确的参数中传递正确的值,并以正确的顺序构造基础 classes。
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)
{}
// ...
};
即使 id
和 name
参数不会被 Programmer
或 Tester
构造函数使用(因为 Employee
基 class 它们被传递给是虚拟的,将由最派生的对象构造,ProjectManager
),我们仍然传递这些值。有几个原因。
- 因为我们已经有了这些
string
个对象,并且构造函数将它们的参数作为引用,所以我们避免了构造将不被使用的临时字符串对象的开销。
- 代码不依赖于
id
和 name
参数未使用的假设。将来对构造函数的更改可能会使用一个或两个参数。通过传递可以避免未来错误的预期值。
问题是,当您调用 ProjectManger
构造函数时,您还调用了 Programmer
和 Tester
的重载构造函数,您调用的版本是那些以参数一为参数的版本std::string
,那些构造函数改变了Employee::id_
的值,实际上你从来没有改变其他值。
要解决问题,您必须更改
ProjectManager(std::string& id, std::string& name, std::string& programming_language, std::string& tool) :
Employee(id, name),
Programmer(programming_language),
Tester(tool)
{}
在
ProjectManager(std::string& id, std::string& name, std::string& programming_language, std::string& tool) :
Employee(id, name),
Programmer("","",programming_language),
Tester("","",tool)
{}
让我们看看下面的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();
}
输出
C:\Users\pc\source\repos\input_cpp_files\cmake-build-debug\input_cpp_files.exe
(id, name, ,)
Process finished with exit code 0
正如我们所见,程序没有给出正确的输出。
预期输出为:
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
如何在 ProjectManager
中实现构造函数以便它们提供正确的输出?
附加源代码
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
您的 4 参数 ProjectManager
构造函数调用 1 参数 Programmer
构造函数,它不设置 programming_language_
成员。 Tester
构造函数也是如此。
所以你的两个 class 的成员变量都没有得到除默认初始化为空字符串之外的任何东西。
解决方案是在正确的参数中传递正确的值,并以正确的顺序构造基础 classes。
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)
{}
// ...
};
即使 id
和 name
参数不会被 Programmer
或 Tester
构造函数使用(因为 Employee
基 class 它们被传递给是虚拟的,将由最派生的对象构造,ProjectManager
),我们仍然传递这些值。有几个原因。
- 因为我们已经有了这些
string
个对象,并且构造函数将它们的参数作为引用,所以我们避免了构造将不被使用的临时字符串对象的开销。 - 代码不依赖于
id
和name
参数未使用的假设。将来对构造函数的更改可能会使用一个或两个参数。通过传递可以避免未来错误的预期值。
问题是,当您调用 ProjectManger
构造函数时,您还调用了 Programmer
和 Tester
的重载构造函数,您调用的版本是那些以参数一为参数的版本std::string
,那些构造函数改变了Employee::id_
的值,实际上你从来没有改变其他值。
要解决问题,您必须更改
ProjectManager(std::string& id, std::string& name, std::string& programming_language, std::string& tool) :
Employee(id, name),
Programmer(programming_language),
Tester(tool)
{}
在
ProjectManager(std::string& id, std::string& name, std::string& programming_language, std::string& tool) :
Employee(id, name),
Programmer("","",programming_language),
Tester("","",tool)
{}