Manipulaci třídu s dlouhým seznamem inicializace a více konstruktérů?

hlasů
12

Mám (pro mě) složitý objekt člena asi 20 údajů, z nichž mnohé jsou ukazatel k jiným odvětvím. Takže pro konstruktoru, mám velký dlouhý, komplexní seznam inicializace. Třída má také tucet různých konstruktérů, které odrážejí různé způsoby, jak může být třída vytvořili. Většina z těchto inicializovat čísla jsou beze změny mezi každou z těchto různých konstruktérů.

Moje obava je, že teď mají velkou sklíčidlo zkopírovaný kód (nebo většinou zkopírován), který, když potřebuji přidat nového člena do skupiny, nemusí dělat to do každého ze seznamů konstruktoru inicializace.

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

Pak opakujte výše pro ostatní výrobci. Existuje nějaký chytrý způsob, jak pomocí výchozí konstruktor pro toto, pak úpravou výsledky ostatních konstruktérů?

Položena 17/04/2009 v 20:48
zdroj uživatelem
V jiných jazycích...                            


12 odpovědí

hlasů
13

Jak se o Refaktor společné pole do základní třídy. Výchozí konstruktor základní třídy by se zabývali inicializace pro nepřeberné množství standardních polí. Bude vypadat nějak takto:

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

Objekt konstruktéři by měla vypadat trochu lépe zvládnutelné, nyní:

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

Podobný charakter iraimbilanja odpověď, ale vyhýbá se přidá vnitřní třídu pro přístup k údajům, které by mohly mít vliv mnoho stávajícího kódu. Pokud jste se již dostali hierarchii tříd, i když to může být obtížné ji zařazovat do základní třídy.

Odpovězeno 18/04/2009 v 14:35
zdroj uživatelem

hlasů
9

Nyní pár let později máme C ++ 11. Pokud jej můžete použít ve svém projektu, máte dvě možnosti:

Jsou-li hodnoty běžné inicializační známa až za běhu, můžete použít delegování konstruktérů, což znamená, že jeden konstruktor volá jiný.

 // 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;
     }
 };

nebo můžete inicializovat členy přímo v definici třídy, pokud jejich hodnoty jsou známy v době kompilace.

class Foo
{
    const int constant = 0;
    int userSet = 0;

public:
    Foo( int userSetArg) : userSet(userSetArg){}
}
Odpovězeno 10/07/2014 v 15:38
zdroj uživatelem

hlasů
5

Ano, je to možné.
Pro jednoduchost budu předstírat, že původní kód je:

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

Refactored Kód je tedy:

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;
};
Odpovězeno 17/04/2009 v 20:57
zdroj uživatelem

hlasů
4

Není co do činění s konstruktéry, ale proč si myslíš, že je nutné vytvořit všechny tyto dílčí objekty dynamicky nového? To není dobrý nápad - byste se měli vyhnout dynamické vytváření kdekoli je to možné. Nedělají všechny ty členy rad - aby byly skutečné objekty.

Odpovězeno 17/04/2009 v 20:53
zdroj uživatelem

hlasů
4

Zvyšte :: Parametr umožňuje snadno implementovat pojmenovaný parametr idiom . Podívejte se na toto vlákno na SO. To nemusí být přesně to, co potřebujete, ale poskytuje určitou flexibilitu, pokud chcete přesměrovat hovory na výchozí ctor.

Odpovězeno 17/04/2009 v 20:52
zdroj uživatelem

hlasů
2

Můžete sdílet svůj společný kód členské funkce soukromá init ().

Příklad:

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
   ...
 } 
Odpovězeno 17/04/2009 v 20:53
zdroj uživatelem

hlasů
1

Chtěl bych použít různými výrobními metodami (statické metody), že by se vrátil zpět inteligentní ptr do vaší třídy. Jména způsob výroby by také pomohla dokument, proč je třeba všechny různé parametry.

Odpovězeno 18/04/2009 v 03:51
zdroj uživatelem

hlasů
1

Budu předmluvu to tím, že jsem se (zřejmě) nejsou znát podrobnosti o vašem systému, nebo omezení, které vedly ke svým designu rozhodnutí.

Jak již bylo řečeno, dobrým pravidlem je, že když začne třída dostat unweildy - v době, kdy začnete klást otázky o tom, jak s ní zacházet :) - to může být čas, aby refaktorovat tuto třídu do několika menších podskupin.

Uvědomte si, že třída má dělat jednu věc velmi dobře . Pokud začnete mít velké třídy, které se snaží dělat příliš mnoho věcí, jste vzdaloval od dobrého OO designu.

Odpovězeno 17/04/2009 v 21:29
zdroj uživatelem

hlasů
1
Object (const string &Name = "", const string &path = "", const bool loadMetadata = false);

To nevyřeší všechny vaše problémy (zejména neexistuje žádný způsob, jak reprezentovat konstruktoru se jménem a loadMetaData), ale bude alespoň kolaps některé z konstruktérů do jedné.

Odpovězeno 17/04/2009 v 21:15
zdroj uživatelem

hlasů
1

Za prvé, budete mít nevracení paměti, pokud nechcete provést odstranění alokovaných objektů v destruktoru. Takže byste měli definovat své destruktor a odstranit předměty tam.

Pokud opravdu potřebujete dynamicky přidělovat členy (I nedoporučujeme, pokud tato třída je vlastníkem objektu člen data), můžete mít vlastní metodu, která dělá všechny inicializace a můžete volat tuto metodu od svých konstruktérů.

Odpovězeno 17/04/2009 v 20:57
zdroj uživatelem

hlasů
0

Stačí dát seznam Inicializátor uvnitř makra a hotovo.

Odpovězeno 17/04/2009 v 22:31
zdroj uživatelem

hlasů
0

Myslíte si opravdu potřebujete 5 různých konstruktérů?

Velmi často se stává, pokud potřebujete převést konstruktérů nechcete také chtít výchozí konstruktor.

Vaše další konstruktéři všechny trvat jen jinou kombinaci stejnou věc. Mohlo by to být lepší nápad mít jen jeden konstruktor, který bere všechny parametry, s možností pro každý parametr, který označuje touhu vyvolat nějaký výchozí hodnota tohoto parametru.

Například:

class Object
{
  Object (const string *Name, // can be NULL
    const string *path, // can be NULL 
    const bool loadMetadata);

};
Odpovězeno 17/04/2009 v 21:01
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more