jeudi 2 août 2012

Delegating constructors

Pas vraiment la fonctionnalité de C++11 qui fera rêver dans les chaumières, mais tout à fait utile dans certains cas, la délégation de constructeurs permet tout simplement d'appeler un constructeur depuis un autre constructeur. Voyons immédiatement un exemple:

#include <string>
#include <iostream>

class A
{
public:
  A():
    _a("abc"),
    _b(5),
    _c(0.4)
  {
    std::cout << "Constructeur par défaut" << std::endl;
  }
  
  A(const std::string & a, double c):
    A()
  {
    _a = a;
    _c = c;
    std::cout << "Deux paramètres" << std::endl;
  }
  
  A(const std::string & message):
    A(message, 0.3)
  {
    std::cout << "Un paramètre" << std::endl;
  }
  
  void print()
  {
    std::cout << _a << ", " << _b << ", " << _c << std::endl;
  }

private:
  std::string _a;
  int _b;
  double _c;
};

int main()
{
  std::cout << "---" << std::endl;
  A a1;
  a1.print();

  std::cout << "---" << std::endl;
  A a2("def", 0.7);
  a2.print();

  std::cout << "---" << std::endl;
  A a3("ghi");
  a3.print();
}

Le programme affiche

---
Constructeur par défaut
abc, 5, 0.4
---
Constructeur par défaut
Deux paramètres
def, 5, 0.7
---
Constructeur par défaut
Deux paramètres
Un paramètre
ghi, 5, 0.3

Il est aisé de suivre les constructeurs pour trouver ceux qui ont été appelés. Notons cependant une petite restriction: lorsque l'on délègue un constructeur, il n'est pas possible d'avoir quoi ce ce soit d'autre dans la liste d'initialisation, que ce soient des appels de classe parente ou de l'initialisation de membres. C'est pour cela que dans l'exemple, dans le second constructeur, _a et _c reçoivent l'affectation dans le corps du constructeur.

Il est plus généralement raisonnable d'avoir un constructeur générique prenant le plus grand nombre de paramètres, et des constructeurs spécifiques qui délèguent au constructeur générique, afin de permettre par exemple certaines restrictions sur les paramètres.

Aucun commentaire: