代码之家  ›  专栏  ›  技术社区  ›  Thomas Jones-Low

处理具有长初始化列表和多个构造函数的类?

  •  13
  • Thomas Jones-Low  · 技术社区  · 17 年前

    我有一个(对我来说)复杂的对象,它有大约20个数据成员,其中许多是指向其他类的指针。因此,对于构造函数,我有一个长长的、复杂的初始化列表。该类还有十几个不同的构造函数,反映了创建该类的各种方式。这些初始化项中的大多数在每个不同的构造函数之间都没有变化。

    我在这里担心的是,我现在有一大堆复制的(或大部分复制的)代码,如果我需要向类中添加新成员,这些代码可能无法进入每个构造函数初始化列表。

    class Object 
    {
        Object();
        Object(const string &Name);
        Object (const string &Name, const string &path);
        Object (const string &Name, const bool loadMetadata);
        Object (const string &Name, const string &path, const bool loadMetadata);
    } 
    
    Object::Object() :
        name(),
        parent_index (0),
        rowData (new MemoryRow()),
        objectFile (),
        rows (new MemoryColumn (object_constants::RowName, OBJECTID, object_constants::ROWS_OID)),
        cols (new MemoryColumn (object_constants::ColName, OBJECTID, object_constants::COLS_OID)),
        objectName (new MemoryColumn(object_constants::ObjName, STRING, object_constants::short_name_len, object_constants::OBJECTNAME_OID)),
        parent     (new MemoryColumn(object_constants::ParentName, STRING, object_constants::long_name_len, object_constants::PARENT_OID)),
        parentIndex (new MemoryColumn(object_constants::ParentIndex, OBJECTID, object_constants::PARENTINDEX_OID)),
        childCount (new MemoryColumn (object_constants::ChildCount, INTEGER, object_constants::CHILD_COUNT_OID)),
        childList (new MemoryColumn (object_constants::ChildList, STRING, object_constants::long_name_len, object_constants::CHILD_OID)),
        columnNames (new MemoryColumn (object_constants::ColumnNames, STRING, object_constats::short_name_len, object_constants::COLUMN_NAME)),
        columnTypes (new MemoryColumn (object_constants::ColumnTypes, INTEGER, object_constants::COLUMN_TYPE)),
        columnSizes (new MemoryColumn (object_constants::ColumnSizes, INTEGER, object_constants::COLUMN_SIZE))
    {}
    

    然后对其他构造函数重复上述步骤。有什么聪明的方法可以使用默认构造函数,然后修改其他构造函数的结果吗?

    12 回复  |  直到 17 年前
        1
  •  15
  •   veefu    17 年前

    将公共字段重构为基类怎么样。基类的默认构造函数将处理大量默认字段的初始化。看起来像这样:

    class BaseClass {
        public:
        BaseClass();
    };
    
    class Object : public BaseClass
    {
        Object();
        Object(const string &Name);
        Object (const string &Name, const string &path);
        Object (const string &Name, const bool loadMetadata);
        Object (const string &Name, const string &path, const bool loadMetadata);
    };
    
    BaseClass::BaseClass() :
        parent_index (0),
        rowData (new MemoryRow()),
        objectFile (),
        rows (new MemoryColumn (object_constants::RowName, OBJECTID, object_constants::ROWS_OID)),
        cols (new MemoryColumn (object_constants::ColName, OBJECTID, object_constants::COLS_OID)),
        objectName (new MemoryColumn(object_constants::ObjName, STRING, object_constants::short_name_len, object_constants::OBJECTNAME_OID)),
        parent     (new MemoryColumn(object_constants::ParentName, STRING, object_constants::long_name_len, object_constants::PARENT_OID)),
        parentIndex (new MemoryColumn(object_constants::ParentIndex, OBJECTID, object_constants::PARENTINDEX_OID)),
        childCount (new MemoryColumn (object_constants::ChildCount, INTEGER, object_constants::CHILD_COUNT_OID)),
        childList (new MemoryColumn (object_constants::ChildList, STRING, object_constants::long_name_len, object_constants::CHILD_OID)),
        columnNames (new MemoryColumn (object_constants::ColumnNames, STRING, object_constats::short_name_len, object_constants::COLUMN_NAME)),
        columnTypes (new MemoryColumn (object_constants::ColumnTypes, INTEGER, object_constants::COLUMN_TYPE)),
        columnSizes (new MemoryColumn (object_constants::ColumnSizes, INTEGER, object_constants::COLUMN_SIZE))
    {}
    

    现在,你的对象构造函数应该看起来更易于管理:

    Object::Object() : BaseClass() {}
    Object::Object (const string &Name): BaseClass(), name(Name) {}
    Object::Object (const string &Name, const string &path): BaseClass(), name(Name), path_(path){}
    Object::Object (const string &Name, const bool loadMetadata): BaseClass(), name(Name){}
    Object::Object (const string &Name, const string &path, const bool loadMetadata): BaseClass(), path_(path) {}
    

        2
  •  12
  •   Knitschi    6 年前

    当公共初始化值仅在运行时已知时,您可以使用委托构造函数,这意味着一个构造函数调用另一个构造函数。

     // function that gives us the init value at runtime.
     int getInitValue();
    
     class Foo
     {
         const int constant;
         int userSet;
    
     public:
         // initialize long member list with runtime values
         Foo() 
           : constant(getInitValue())
           , userSet(getInitValue())
         {}
    
         // other constructors with arguments
         Foo( int userSetArg) 
           : Foo()
           , userSet(userSetArg) 
         {
         }
     };
    

    或者,如果在编译时已知成员的值,则可以直接在类定义中初始化成员。

    class Foo
    {
        const int constant = 0;
        int userSet = 0;
    
    public:
        Foo( int userSetArg) : userSet(userSetArg){}
    }
    
        3
  •  5
  •   Iraimbilanja Iraimbilanja    17 年前

    是的,这是可能的。

    class Foo {
    public:
        Foo() : a(0), b(1), x() { }
        Foo(int x) : a(0), b(1), x(x) { }
    
        int get_a() const { return a; }
        int get_b() const { return b; }
        int get_x() const { return x; }
    private:
        int a, b, x;
    };
    

    重构后的代码是:

    class Foo {
    public:
        Foo() : x() { }
        Foo(int x) : x(x) { }
    
        int get_a() const { return common.a; }
        int get_b() const { return common.b; }
        int get_x() const { return x; }
    private:
        struct Common {
            Common() : a(0), b(1) { }
            int a, b;
        } common;
        int x;
    };
    
        5
  •  4
  •   anon anon    17 年前

        6
  •  2
  •   Naveen    17 年前

    class Object
    {
     public:
       Object(const string &Name);
       Object(const string &Name, const string &path);
       ...
     private:
       void init();
     };
    
     Object::Object(const string &Name)
     {
       init();
       ...
     }
    
     Object::Object(const string &Name, const string &path)
     {
       init();
       ...
     }
    
     void Object::init()
     {
    //intialization stuff
       ...
     } 
    
        7
  •  1
  •   Cătălin Pitiș    17 年前

    首先,如果不在析构函数中删除分配的对象,就会发生内存泄漏。因此,您应该定义析构函数并删除其中的对象。

        8
  •  1
  •   David Thornley    17 年前
    Object (const string &Name = "", const string &path = "", const bool loadMetadata = false);
    

        9
  •  1
  •   James Eichele Bernard Igiri    17 年前

    记住,一堂课应该做 事物 很好 如果你开始有大型类试图做太多的事情,那么你就偏离了良好的面向对象设计。

        10
  •  1
  •   chrish    17 年前

    我会使用不同的工厂方法(静态方法),这些方法会将智能ptr返回给你的类。工厂方法名称也有助于记录为什么需要所有不同的参数。

        11
  •  0
  •   John Dibling    17 年前

    如果你需要转换构造函数,你通常不需要默认构造函数。

    例如:

    class Object
    {
      Object (const string *Name, // can be NULL
        const string *path, // can be NULL 
        const bool loadMetadata);
    
    };
    
        12
  •  0
  •   BigSandwich    17 年前

    只需将初始化器列表放入MACRO中即可。