Constructori multipli pentru clase in Cpp

Stau acum si fac niste modificari / optimizari intr-un proiect, scris, de sigur, de altcineva. Si, surpriza, ca de fiecare data cand faci review ( caci asta faci inainte de a te apuca sa modifici jumate din codul care e acolo ) gasesti ceva care nu e in regula si care te deranjeaza… ceva atat de mic… dar…

Deci, sa trec la tema. Dupa cum se stie in Cpp se pot defini mai multi constructori, astfel, un exemplu:

class Cluster {
private:
  int a;
  int b;
  int c;
  int d;  //aceasta clasa contine foarte multe variabile interne
public:
  //constructorul creeaza clasa pornind de la alta clasa
  Cluster( CAnotherClass *_class );
  // ctor de copiere
  Cluster( Cluster *_cluster );
  // ctor default
  Cluster( );
};

La prima vedere, acest cod pare nevinovat, dar daca te uiti in implementarea constructorilor, ar arata cam astfel :

Cluster::Cluster( CAnotherClass *_c ) : a( _c->a )
    , b( _c->b )
    , c( _c->c )
    , d( _c ->d )
{ /* no code */ }
Cluster::Cluster( Cluster *_c ) : a( _c->a )
    , b( _c->b )
    , c( _c->c )
    , d( _c ->d )
{ /* no code */ }
Cluster::Cluster( ) : a( 0 )
    , b( 0 )
    , c( 0 )
    , d( 0 )
{ /* no code */ }

in fine, mai pui si constructorul de copiere… si ai 100 de linii de cod cu constructori doar.

Partea nasoala apare doar atunci cand vrei sa adaugi / scoti un membru nou din clasa… ceea ce inseamna ca trebui sa modifici toti constructorii… Poate nu e o problema modificarea constructorilor, dar ce faci daca uiti sa faci modificarile intr-un constructor ( daca ai multe surse se poate intimpla foarte des ).

Pentru a face putin ordine in toti constructorii se procedeaza astfel :
1. se alege o functie ( doar una, posibil privata ) care va avea rolul de a atribui valori membrilor privati

Cluster::set( int a, int b, int c, int d );

2. celalti constructori apeleaza doar functia de set definit la punctul 1.

Cluster::Cluster( CAnotherClass *_c )
{
   set( _c->a, _c->b, _c->c, _c->d );
}
Cluster::Cluster( Cluster *_c )
{
   set( _c->a, _c->b, _c->c, _c->d );
}
Cluster::Cluster( )
{
   set( 0, 0, 0, 0 );
}

Prin o astfel de abordare a problemei aveti doar de castigat din urmatoarele motive:

1. atunci cand adaugi un membru nou in clasa, modifici functia set, iar functiile care folosesc functia set o sa dea eroare la compilare ( compilatorul aici e un ajutor pentru tine, iar in celalalt caz trebuie sa modifici manual in fiecare constructor cu posibilitatea ca poti sa omiti undeva modificarile, compilatorul nu iti da nici o eroare, iar la rulare se poate apela un constructor care nu l-ai update-at si care ti-a lasat noua variabila neinitializata ).

2. daca la un moment dat iti dai seama ca o variabila trebuie tratata mai speciala, sa ii faci nishte prelucrari inainte, atunci acest cod nou o sa il scrii doar in functia de set, nu o sa duplici mai apoi codul in toti constructorii.

3. clasa este mult mai bine structurata si ofera o logica celui care o sa ii face review mai tarziu.

cred ca atat.