Les Constructeurs
Lors de l'instanciation d'un objet, le compilateur invoque un constructeur pour assigner des valeurs initiales aux membres de l'objet. Toutefois, ce processus relève de l'affectatino plutôt que de l'initialisation stricte, car l'initialisation ne doit survenir qu'une seule fois, tandis que le corps du constructeur permet plusieurs affectations.
class Coordonnee
{
public:
Coordonnee(int x_val, int y_val)
{
_abscisse = x_val;
_ordonnee = y_val;
}
private:
int _abscisse;
int _ordonnee;
};
Listes d'Initialisation
Les listes d'initialisation offrent une vraie initialisation. Elles se composent d'une liste de membres séparés par des virgules, chacun suivi de sa valeur entre parenthèses, précédée de deux-points.
class Coordonnee
{
public:
Coordonnee(int x_val, int y_val)
: _abscisse(x_val)
, _ordonnee(y_val)
{
}
private:
int _abscisse;
int _ordonnee;
};
Sans liste d'initialisation, l'assignation dans le constructeur équivaut à déclarer une variable puis lui attribuer une valeur, ce qui n'est pas une initialisation. Les références, les membres const et les types personnalisés sans constructeur par défaut doivent être initialisés via cette liste.
Membres Statiques
Les membres statiques sont partagés par toutes les instances de la classe. Les variables statiques doivent être définies hors de la classe.
class Moniteur
{
public:
Moniteur() { ++_total; }
Moniteur(const Moniteur& src) { ++_total; }
static int compter() { return _total; }
private:
static int _total;
};
int Moniteur::_total = 0;
int main()
{
Moniteur m1;
Moniteur m2;
Moniteur tableau[3];
cout << Moniteur::compter() << endl; // Affiche 5
return 0;
}
Caractéristiques : les membres statiques appartiennent à la classe, non à une instance ; les variables statiques sont définies sans le mot-clé static ; elles sont accessibles via la classe ou un objet ; les fonctions statiques n'ont pas de pointeur this et ne peuvent accéder aux membres non statiques.
Fonctions et Classes Amies
L'amitié permet d'outrepasser l'encapsulation, mais augmente le couplage. Les fonctions amies sont utiles pour surcharger des opérateurs.
class Date
{
friend ostream& operator<<(ostream& sortie, const Date& obj);
friend istream& operator>>(istream& entree, Date& obj);
public:
Date(int jour = 1, int mois = 1, int annee = 2000)
: _jour(jour)
, _mois(mois)
, _annee(annee)
{}
private:
int _jour;
int _mois;
int _annee;
};
ostream& operator<<(ostream& sortie, const Date& obj)
{
sortie << obj._jour << "/" << obj._mois << "/" << obj._annee;
return sortie;
}
istream& operator>>(istream& entree, Date& obj)
{
entree >> obj._jour >> obj._mois >> obj._annee;
return entree;
}
Les fonctions amies peuvent accéder aux membres privés, ne sont pas des fonctions membres, et ne peuvent être const. Une classe amie a toutes ses fonctions membres comme amies d'une autre classe, avec amitié unidirectionnelle et non transitive.
Classes Internes
Une classe définie dans une autre est une classe interne, indépendante de la classe externe. Elle est automatiquement amie de la classe externe.
class Enveloppe
{
private:
static int _valStatique;
int _valInstance;
public:
class Noyau
{
public:
void executer(const Enveloppe& ext)
{
cout << _valStatique << endl;
cout << ext._valInstance << endl;
}
};
};
int Enveloppe::_valStatique = 10;
int main()
{
Enveloppe::Noyau noyau;
noyau.executer(Enveloppe());
return 0;
}
Les classes internes peuvent être définies dans les sections public, protected ou private, et accèdent directement aux membres statiques et énumérés de la classe externe. La taille de la classe externe est indépendante de la classe interne.