代码之家  ›  专栏  ›  技术社区  ›  CaptainCodeman

如何将“设置”从派生构造函数传递给基构造函数

  •  0
  • CaptainCodeman  · 技术社区  · 2 年前

    我有一个类,在构造函数中有一组参数,如下所示:

    class Foo {
      public:
        Foo(int opt_1=0, int opt_2=100, std::string & opt_3="", bool opt_4=true);
    };
    

    然后我说,这变得很混乱,让我们把所有这些选项放在设置类中:

    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) {}
    };
    

    如何使用新的设置类来执行此操作?

    我想我可以为设置设置一个构造函数,它允许设置所有的变量,但这样就达不到全部目的了,不是吗?

    0 回复  |  直到 2 年前
        1
  •  1
  •   alagner    2 年前

    免责声明:对于OP,我不知道有多少种可能性,这取决于实际用例、编码约定和需求。 下面,我将针对我认为应该在问题背景下说的内容,提出我的主观选择。同样,这份清单并非详尽无遗。

    在我看来,这里值得一提的主要可能性是:

    1. 制作一些返回设置类的工厂方法。
    2. 使用aggreate初始化。
    3. 利用生成器模式。

    代码的主要特点是 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()){}
    };
    

    如果没有默认构造函数,则可以使用aggreate初始化: 它是否违背了目的?我不知道,你告诉我;) 使用aggreate初始化,可以轻松省略最后一个参数:

    #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有两名施工人员: Error when using in-class initialization of non-static data member and nested class constructor ) 顺便说一句,这会变得更好,并放弃了使用C++20指定初始值设定项的下一个选项:

    struct BabyFoo : public Foo
    {
        BabyFoo() : Foo({.opt_4=false}){} //note that this is available since C++20
    };
    

    如果您不喜欢这些解决方案中的任何一个,您可以查看生成器模式:

    #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()){}
    };
    

    请注意,构建器可能应该直接构建Foo,而不是其设置,但同样,这取决于上下文。