Vous êtes sur la page 1sur 6

Question 1 – Composition d’objets

Donnez l’affichage que produit le code suivant.

Attention ! Respectez la casse (minuscules/majuscules) des chaînes affichées.

class D B::B()
{ {
public : cout << "GRAM ";
D(); B_attribut_1 = 0;
D(int n); }
~D();
private : B::B(int n) : B_attribut_1(n)
int D_attribut_1; {
}; cout << "gram ";
}
D::D()
{ B::~B()
cout << "AM "; {
D_attribut_1 = 0; cout << "pique ";
} }

D::D(int n) : D_attribut_1(n) class A


{ {
cout << "am "; public :
} A();
A(int n);
D::~D() ~A();
{ private :
cout << "COLEGRAM.\n"; int A_attribut_1;
} B A_attribut_2;
};
class C
{ A::A()
public : {
C(); cout << "PIQUE ";
C(int n); A_attribut_1 = 0;
~C(); }
private :
int C_attribut_1; A::A(int n) : A_attribut_1(n)
D C_attribut_2; {
}; cout << "colegram.\n";
}
C::C() : C_attribut_2(1)
{ A::~A()
cout << "stram "; {
C_attribut_1 = 0; cout << "et ";
} }

C::C(int n) : C_attribut_1(n) void f()


{ {
cout << "STRAM "; A objet_A;
} }

C::~C() void main()


{ {
cout << "ET "; f();
} }
class B
{
public :
B();
B(int n);
~B();
private :
int B_attribut_1;
C B_attribut_2;
};

Page 2 sur 8
am stram GRAM PIQUE et pique ET COLEGRAM.

Question 2 – Implémentation d’une classe

a) (2 pts) Soit une classe Personne, possédant les attributs Prenom, Nom et DateDeNaissance, ainsi que les
méthodes permettant de lire ces attributs, et un constructeur qui crée un objet Personne à partir de son
prénom, de son nom et de sa date de naissance. L’attribut DateDeNaissance est un objet de la classe Date,
qui possède trois attributs privés de type entier Jour, Mois et Annee. Donnez le code de ces classes et des
méthodes, ainsi que celui de leurs constructeur. Attention ! Vous devez donner l’intégralité du code
permettant à ces lignes de fonctionner :

Personne personne("Pierre", "Quiroule", 25, 9 , 1976);


cout << personne.lire_prenom() << " " << personne.lire_nom() << " ";
cout << personne.lire_date().lire_jour() << " ";
cout << personne.lire_date().lire_mois() << " ";
cout << personne.lire_date().lire_annee() << endl;

class Date string lire_prenom() const;


{ string lire_nom() const;
public: Date lire_date() const;
Date(int j, int m, int a); private:
int lire_jour() const; string Prenom;
int lire_mois() const; string Nom;
int lire_annee() const; Date DateDeNaissance;
private: };
int jour;
int mois; Personne::Personne(const string& p,
int annee; const string& n,
}; const int& j,
const int& m,
Date::Date(int j, int m, int a) const int& a)
: jour(j), mois(m), annee(a) : Prenom(p),
{} Nom(n),
DateDeNaissance(Date(j, m, a))
int Date::lire_jour() const {}
{
return jour; string Personne::lire_prenom() const
} {
return Prenom;
int Date::lire_mois() const }
{
return mois; string Personne::lire_nom() const
} {
return Nom;
int Date::lire_annee() const }
{
return annee; Date Personne::lire_date() const
} {
return DateDeNaissance;
class Personne }
{
public:
Personne(const string& p,
const string& n,
const int& j,
const int& m,
const int& a);

b) Expliquez brièvement pourquoi il n’a pas été pertinent de définir un constructeur par défaut pour cette
classe.
Un constructeur par défaut créerait une personne qui n’aurait ni prénom, ni nom, ni date
de naissance. Un tel objet n’aurait aucune utilité dans une application courante.

c) (2 pts) Donnez le code de la surdéfinition d’un opérateur <= permettant de comparer deux objets quidam_1
et quidam_2 de la classe Personne, et qui retourne TRUE si quidam_1 est plus jeune ou du même âge que
quidam_2, FALSE sinon.

bool Personne::operator<=(const Personne& quidam) const


{
if (lire_date().lire_annee() > quidam.lire_date().lire_annee())
return true;
else
if (lire_date().lire_annee() < quidam.lire_date().lire_annee())
return false;

if (lire_date().lire_mois() > quidam.lire_date().lire_mois())


return true;
else
if (lire_date().lire_mois() < quidam.lire_date().lire_mois())
return false;

if (lire_date().lire_jour() >= quidam.lire_date().lire_jour())


return true;
else return false;
}
Ne pas oublier d’ajouter la ligne suivante dans la section public de la classe Personne :

bool operator<=(const Personne& quidam) const;

Question 3 – Classe générique

Soit la classe Stack et ses méthodes suivantes qui implémentent une pile d’entiers grâce à un tableau dynamique.

class Stack int Stack::pop()


{ {
public : int ret;
Stack(int n);
~Stack(); if (nelem > 0)
void push(int n); ret = stackPtr[--nelem];
int pop(); return ret;
bool full(); }
bool empty();
int get_nelem(); bool Stack::full()
private: {
int dim; return (nelem == dim);
int *stackPtr; }
int nelem ;
}; bool Stack::empty()
{
Stack::Stack(int n) return (nelem == 0);
{ }
stackPtr = new int[dim = n];
nelem = 0; int Stack::get_nelem()
} {
return this->nelem;
Stack::~Stack() }
{
delete [] stackPtr;
}

void Stack::push(int n)
{
if (nelem < dim)
stackPtr[nelem++] = n;
}

Page 4 sur 8
a) Modifier le code de la classe Stack et de ses méthodes, de façon à ce qu’elles définissent une classe
générique implémentant une pile de données de type quelconque T.

template< typename T > template< typename T >


class Stack T Stack<T>::pop()
{ {
public : T ret;
Stack(int n);
~Stack(); if (nelem > 0)
void push(T n); ret = stackPtr[--nelem];
T pop();
bool full(); return ret;
bool empty(); }
int get_nelem();
private: template< typename T >
int dim; bool Stack<T>::full()
T *stackPtr; {
int nelem; return (nelem == dim);
}; }
template< typename T > template< typename T >
Stack<T>::Stack(int n) bool Stack<T>::empty()
{ {
stackPtr = new T[dim = n]; return (nelem == 0);
nelem = 0; }
}
template< typename T >
template< typename T > int Stack<T>::get_nelem()
Stack<T>::~Stack() {
{ return this->nelem;
delete [] stackPtr; }
}

template< typename T >


void Stack<T>::push(T n)
{
if (nelem < dim)
stackPtr[nelem++] = n;
}

b) Soit la méthode print suivante, qui affiche le contenu de la pile :

void Stack::print()
{
int i;

for (i = 0; i < nelem; i++) cout << stackPtr[i] << " ";
cout << "\n";
}

Donnez le code effectuant la surdéfinition de l’opérateur <<, de façon à ce que l’instruction « cout <<
maPile », où maPile est un objet de type Stack, produise le même résultat que l’instruction
« maPile.print() » .

template< typename T >


ostream& operator<<(ostream& out, const Stack< T >& stack)
{
for (int i = 0; i < stack.nelem; i++) out << stack.stackPtr[i] << " ";

return out;
}
Question 4 - Héritage

a) Expliquez en moins de 5 lignes à quoi sert le mot-clé protected.

Un attribut ou une méthode d’une classe A déclaré protected peut être accédé par les
objets d’une classe B dérivée de A, ce qui n’est pas le cas des attributs et méthodes
privés de A. À noter que les fonctions amies de A peuvent accéder à tous les attributs
de A, même les attributs privés.

b) Donnez un exemple détaillé illustrant avec précision votre explication précédente.

Les attributs mLargeur et mHauteur de la int CPolygon::get_largeur()


classe CPolygon sont déclarés protégés, {
de façon à ce que les méthodes return mLargeur;
calcule_surface des classes dérivées }int CPolygon::get_hauteur()
CRectangle et CTriangle puissent y {
accéder. return mHauteur;
}
class CPolygon
{ class CRectangle : public CPolygon
public : {
CPolygon(); public :
CPolygon(int x, int y); int calcule_surface();
void set_dimensions(int x, int y); };
int get_largeur();
int get_hauteur(); int CRectangle::calcule_surface()
protected : {
int mLargeur; return (mLargeur * mHauteur);
int mHauteur; }
};
class CTriangle : public CPolygon
CPolygon::CPolygon() {
{} public :
int calcule_surface();
CPolygon::CPolygon(int x, int y) : };
mLargeur(x), mHauteur(y)
{} int CTriangle::calcule_surface()
{
void CPolygon::set_dimensions(int x, int return ((mLargeur * mHauteur) / 2);
y) }
{
mLargeur = x;
mHauteur = y;
}

Page 6 sur 8
Question 5 – Allocation dynamique

Soit l’interface de la classe MyString suivante.

class MyString
{
public :
MyString(); // constructeur I (par défaut)
MyString(char * c); // constructeur II (à partir d'une chaîne)
MyString(const CMyString & s); // constructeur III (de recopie)
~MyString();
MyString & operator = (const CMyString & s);
int operator == (CMyString & s);
MyString operator + (CMyString & s);
char & operator [] (int n);
void Print();
int GetLength();
private :
int m_length; // longueur de la chaîne
char *m_ptr; // pointeur sur la chaîne
};

a) Expliquez pourquoi un constructeur de recopie est nécessaire ici.

La classe MyString possède un attribut char *m_ptr, qui est un pointeur vers un tableau dynamique. Un
constructeur de recopie effectue généralement les allocations mémoire sur le tas requises au moment de la
copie d’un objet. Si l’on veut pouvoir recopier une chaîne MyString, un tel constructeur est nécessaire.

b) Énumérez toutes les situations où un constructeur de recopie est appelé.

Le constructeur de recopie est appelé toutes les fois où un objet créé antérieurement A doit être recopié dans
un objet nouvellement créé B, c’est-à-dire :
• Lors d’une affectation : B = A .
• Lors du passage d’un objet par valeur à une fonction.

c) Donnez le code du constructeur de recopie.

MyString::MyString(const MyString &c)


{
m_ptr = new char[m_length = c.m_length];
for (int i = 0; i < m_length; i++) m_ptr[i] = c.m_ptr[i];
}

d) Donnez le code de la surdéfinition de l’opérateur de concaténation +.

// ATTENTION : la valeur de retour doit être transmise par valeur !


MyString MyString::operator +(MyString &s)
{
MyString res;
res.m_ptr = new char[res.m_length = m_length + s.m_length];

for (int i = 0; i < m_length; i++) res.m_ptr[i] = m_ptr[i];


for( i = 0; i < s.m_length; i++) res.m_ptr[i+m_length] = s.m_ptr[i];
return res;
}

Page 7 sur 8

Vous aimerez peut-être aussi