Handling a class with a long initialization list and multiple constructors?
How about refactor the common fields into a base class. The default constructor for the base class would handle initialization for the plethora of default fields. Would look something like this:
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))
{}
Your Object constructors should look a little more manageable, now:
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) {}
Similar in nature to Iraimbilanja's answer, but avoids adding an inner-class for accessing data, which might impact a lot of existing code. If you've already got a class hierarchy, though, it may be difficult to factor it into a base class.
Yes, it's possible.
For simplicity I'll pretend that the original code is:
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;
};
The refactored code, then, is:
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;
};
Now a couple of years later we have C++ 11. If you can use it in your project you have two options:
When the common initialization values are only known at runtime you can use delegating constructors, which means one constructor calls another.
// 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)
{
}
};
or you can initialize the members directly in the class definition if their values are known at compile time.
class Foo
{
const int constant = 0;
int userSet = 0;
public:
Foo( int userSetArg) : userSet(userSetArg){}
}