我有一个类,在构造函数中有一些参数,像这样:
class Foo {
public:
Foo(int opt_1=0, int opt_2=100, std::string & opt_3="", bool opt_4=true);
};
然后我说,这有点乱了,我们把这些选项放到Settings类中吧
class Foo {
public:
struct Settings {
int opt_1;
int opt_2;
std::string opt_3;
bool opt_4;
Settings() : opt_1(0), opt_2(100), opt_3(""), opt_4(true) {}
}
Foo (const Settings &settings = Settings());
};
的想法是,你设置你的设置,然后构造Foo对象。但是如何从派生类中构造呢?假设我有一个派生类BabyFoo,它具有特定的设置值。之前我可以说:
class BabyFoo : public Foo {
public:
BabyFoo() : Foo(0, 500, "babyfoo", false) {}
};
我如何用新的设置类做到这一点?
我想我可以有一个允许设置所有变量的构造函数,但那样就违背了整个目的,不是吗?
免责声明:我不能说OP,有各种各样的可能性取决于实际用例,编码惯例和需求。下面,我将提出我的主观选择,即我认为在这个问题的背景下应该说什么。同样,这个列表并不详尽。
说到这一点,在我看来,这里值得一提的主要可能性是:
- 创建一些返回Settings类的工厂方法。 使用聚合初始化。
- 使用构建器模式
您的代码的主要问题是,Settings
只有默认构造函数。在这种情况下,你必须在某个地方默认构造它,然后传递它。
#include <string>
class Foo {
public:
struct Settings {
int opt_1;
int opt_2;
std::string opt_3;
bool opt_4;
Settings() : opt_1(0), opt_2(100), opt_3(""), opt_4(true) {}
};
Foo (const Settings &settings = Settings());
};
struct BabyFoo : public Foo
{
static Foo::Settings makeFooSettings()
{
Foo::Settings retval;
retval.opt_1=1;
retval.opt_2=22;
retval.opt_3="abcd";
retval.opt_4=false;
return retval;
}
BabyFoo() : Foo(makeFooSettings()){}
};
如果没有默认构造函数,聚合初始化可以使用:它是否违背了目的?我不知道,你告诉我吧。对于聚合初始化,最后一个参数可以很容易地省略:
#include <string>
using namespace std::literals::string_literals;
class Foo {
public:
struct Settings
{
int opt_1 {0};
int opt_2 {100};
std::string opt_3{"abcd"s};
bool opt_4{true};
};
Foo(const Settings& s);
Foo();
};
struct BabyFoo : public Foo
{
BabyFoo() : Foo({8,42}){}
};
(Foo中的两个构造函数由于:使用类内初始化非静态数据成员和嵌套类构造函数时出现错误)顺便说一句,这变得更好了,有点放弃了c++ 20指定初始化式的下一个选项:
struct BabyFoo : public Foo
{
BabyFoo() : Foo({.opt_4=false}){} //note that this is available since C++20
};
如果你不喜欢这些解决方案,你可以看看builder模式:
#include <string>
using namespace std::literals::string_literals;
class Foo {
public:
struct Settings
{
int opt_1 {0};
int opt_2 {100};
std::string opt_3{"abcd"s};
bool opt_4{true};
class Builder
{
public:
Builder& withOpt1(int o) {o1=o; return *this;}
Builder& withOpt2(int o) {o2=o; return *this;}
Builder& withOpt3(const std::string& o) {o3=o; return *this;}
Builder& withOpt1(bool o) {o4=o; return *this;}
Settings build() const {return Settings{o1,o2,o3,o4};}
private:
int o1{};
int o2{};
std::string o3{};
bool o4{};
};
};
Foo(const Settings& s);
Foo();
};
struct BabyFoo : public Foo
{
BabyFoo() : Foo(Foo::Settings::Builder().withOpt3("abc").build()){}
};
注意,也许Builder应该直接构建Foo,而不是它的设置,但是,这取决于上下文。