Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Exam Corrig

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 34

EXAMENS CORRIGÉS

Programmation Orienté Objet avec C++

Filière : Sciences Mathématiques et Informatique


Automne 2013

Mohamed EL ANSARI
Enseignant Chercheur
Département d’Informatique
Faculté des Sciences, Université Ibn Zohr
Agadir
Ce document présente la solution des examens / contrôles proposés, en programmation
orientée objet C++, pour les filières Sciences Mathématiques et Applications (SMA) et
Sciences Mathématiques et Informatique (SMI) entres les années 2005 et 2010. Le cours
est dispensé en semestre 5 pour les deux filières.

Mohamed El Ansari Page 2 sur 34


Département de Mathématiques & Informatique
Faculté des Sciences, Agadir
Contrôle de C++, SMI5-SM5, 28/12/2005, Durée: 1h30mn
M. EL ANSARI

Exercice 1
Soit le programme C++ suivant:

#include <iostream.h>
main() {
int x[3] = { 3, 6, 11 }; int y = 4;int &z = y;
cout << "1," << x[0] <<","<< x[1] <<","<< y <<","<< z<< endl;
int * p = &x;int * p = x; *p = 5;
cout << "2," << x[0] <<","<< x[1] <<","<< y<<","<< z << endl;
int * q = &y;int * q = y;*q = 7;
cout << "3," << x[0] <<","<< x[1] <<","<< y <<","<< z <<endl;
q = new int; if (q!=NULL) *q = 2; delete q;
cout << "4," <<x[0] <<","<< x[1] <<","<< y <<","<< z << endl;
*(++p) = 8;
cout <<"5," << x[0] <<","<< x[1] <<","<< y <<","<< z << endl;
z =*(x+2)-2;
cout << "6," << x[0] <<","<< x[1] <<","<< y <<","<< z <<endl; getchar();
}

1. Quel est le nom du rapport entrenu par les variables z et y ? par les variables p et
x?

2. Trouver et supprimer les 2 instructions incorrectes.

3. Donner la sortie du programme.

Exercice 2
Donner la sortie du programme C++ suivant. Préciser le nombre d’objets créés et celui
d’objets détruits.

#include<iostream.h>
class point{ int abs, ord;
public:
point(){
cout<<"++ point par defaut"<<endl; abs=ord=0;
}
point(int a, int b){
cout<<"++ point normal"<<endl; abs=a; ord=b;
}

Mohamed El Ansari Page 3 sur 34


point(point & p){
cout<<"++ point clonage"<<endl; abs=p.abs; ord=p.ord;
}
~point(){
cout<<"-- point "<<endl;
}
};

class droite{ point s1,s2;


public:
droite(){
cout<<"++ droite par defaut"<<endl;
}
droite(int a, int b, int c, int d):s1(a,b),s2(c,d){
cout<<"++ droite normal"<<endl;
}
~droite(){
cout<<"-- droite "<<endl;
}
};
void main(){
point a, b(1,2);
point *d=new point(b);
point *e=new point;
droite t(1,2,3,4);
}

Exercice 3
Définir une classe Cha^
ıne utilisable pour manipuler des chaı̂nes de caractères et dont la
seule donnée membre est un tableau dynamique de caractères (pointeur), tab. On la
munira des méthodes suivantes :

• un constructeur reçevant en paramètre un pointeur sur caractère (avec "" comme


valeur par défaut), servant initialiser la donnée membre tab avec une copie de cette
chaı̂ne de caractères,

• un constructeur de copie,

• un destructeur (pourquoi est-il nécessaire!?),

• une méthode length donnant la longueur de la donnée membre tab,

• une méthode concat qui reçoit en paramètre une Chaı̂ne C et retourne une nouvelle
Chaı̂ne dont la donnée membre est la concaténation de tab et de la chaı̂ne de
caractères de C,

• une méthode permettant d’afficher tab.

Mohamed El Ansari Page 4 sur 34


Ecrire un petit programme d’application qui déclare deux instances s1 et s2 de Chaı̂ne en
initialisant respectivement leurs contenus à "bon" et "jour", puis qui crée une instance
s3 de Chaı̂ne en concaténant s1 et s2 et affiche s3.

Mohamed El Ansari Page 5 sur 34


Correction
Exercice 1
1. Le rapport entretenu par z et y : z est une référence sur y
Le rapport entretenu par p et x : p est pointeur sur x.

2. Les deux instructions incorrectes sont :

• int * p = &x;
• int * q = y;

3. La sortie du programme apres sa correction:

1,3,6,4,4
2,5,6,4,4
3,5,6,7,7
4,5,6,7,7
5,5,8,7,7
6,5,8,9,9

Exercice 2
• La sortie du programme est :

++ point par defaut


++ point normal
++ point clonage
++ point par defaut
++ point normal
++ point normal
++ droite normal
-- droite
-- point
-- point
-- point
-- point

• Le nombre d’objets créés : 7 (6 points et 1 droite)

• Le nombre d’objets détruits : 5 (4 points et 1 droite)

Les deux points pointés par les deux pointeurs d et e ne se sont pas détruits. Il faut
expliciter leurs destruction en utililisant delete

Mohamed El Ansari Page 6 sur 34


Exercice 3
#include<iostream>
using namespace std;
#include<string.h>

class chaine{
char * tab;
public :
chaine(char *s=""){
tab = new char[strlen(s)+1];
strcpy(tab,s);
}

chaine(const chaine & ch){


tab = new char[strlen(ch.tab)+1];
strcpy(tab,ch.tab);
}

~chaine(){
delete tab;
}

int length(){
return strlen(tab);
}

void affiche(){
cout<<tab<<endl;
}

chaine concat(chaine c);


};

chaine chaine::concat(chaine c){


unsigned int i, larg=strlen(c.tab)+strlen(tab);
chaine res;
res.tab = new char[larg+1];
for(i=0;i<larg;i++)
if (i<strlen(tab))
res.tab[i]=tab[i];
else
res.tab[i]=c.tab[i-strlen(tab)];
return res;
}

Mohamed El Ansari Page 7 sur 34


main(){
char* s="Bon";
chaine tt(s), t("jour");
cout<<tt.length()<<endl;
cout<<t.length()<<endl;
tt.affiche();
t.affiche();
chaine ttt=tt.concat(t);
ttt.affiche();
}

Mohamed El Ansari Page 8 sur 34


Département de Mathématiques & Informatique
Faculté des Sciences, Agadir
Epreuve de C++, SMI5-SM5, 2005/2006, Durée: 1h30mn
M. EL ANSARI

Exercice 1 (16pts):
Réaliser une classe pile nommée ensemble_entiers permettant de manipuler des
ensembles de nombres entiers. Leséléments seront conservés dans un tableau qui sera
alloué dynamiquement par le constructeur de la classe, et qui sera détruit par le
destructeur. Les données membres permettront de connaı̂tre :
• l’adresse du tableau (int *adr),
• le nombre maximum d’éléments du tableau (int dim),
• et le nombre courant d’éléments dans le tableau (int nelem).
La classe comportera les fonctions membres suivantes:
• ensemble entiers(int n): constructeur allouant dynamiquement un
emplacement de n entiers. Si la valeur de n n’est pas fournie, le constructeur
allouera par défaut un emplacement de vingt entiers,
• ensemble entiers(ensemble entiers & e):constructeur de recopie,
• ensemble entiers(): destructeur;
• void empile(int p): ajoute l’entier p sur la pile;
• int depile(): fournit la valeur de l’entier situé en haut de la pile, en le supprimant
de la pile,
• int pleine(): fournit la valeur 1 si la pile est pleine, 0 sinon,
• int vide(): fournit 1 si la pile est vide; 0 sinon,
• int appartient(int p): fournit 1 si l’entier p appartient à la pile, sinon.
Surcharge des opérateurs: Introduisez les opérateurs >, < et + tels que si p, q et r sont
des objets de type ensemble entiers et n une variable entière:
• p<n ajoute la valeur de n sur la pile p (en ne renvoyant aucune valeur),
• p>n supprime la valeur du haut de la pile;
• r=p+q; r sera la concaténation des deux objets p et q.
On prévoira pour cela trois fonctions amies.
Comment pourrait-on adapter la classe ensemble entiers pour qu’elle dispose d’une
fonction membre nbre pile fournissant le nombre d’objets créés à un instant donné.
Ecrire un petit programme d’utilisation permettant de rentrer au clavier 20 nombres
entiers quelconques et de les stocker dans un objet de type ensemble entiers.

Mohamed El Ansari Page 9 sur 34


Exercice 2 (4pts):
Ecrire la macro-fonction qui calcule l’expression x*(x+1). Puis la fonction inline qui fait
de même. Montrer et expliquer sur un exemple que l’appel n’est pas réalisé correctement
avec la macro-fonction alors qu’il l’est avec la fonction.

Mohamed El Ansari Page 10 sur 34


Correction
Exercice 1
#include<iostream.h> const int MAX = 20;

class ensemble_entiers{
int dim;
int *adr;
int nelem;
static int nbobjets;
public:
ensemble_entiers(int n=MAX){
adr=new int[dim=n];
nelem=0;
nbobjets++;
}
ensemble_entiers(ensemble_entiers & p){
adr=new int [dim=p.dim];
nelem=p.nelem;
int i;
for(i=0;i<nelem;i++) adr[i] = p.adr[i];
nbobjets++;
}
~ensemble_entiers(){delete [] adr; nbobjets--;}
void empile(int p){
if (nelem < dim) adr[nelem++] = p;
}
int depile(){if (nelem > 0) return adr[--nelem];
else return 0;
}
int pleine(){return (nelem==dim);}
int vide(){return (nelem == 0);}

int appartient(int p){


int i; int t=0;
for (i=0;i<nelem;i++)
if (adr[i]==p) {t=1;break;}
return t;
}
friend void operator<(ensemble_entiers &, int);
friend void operator>(ensemble_entiers &, int &);
friend ensemble_entiers operator+(ensemble_entiers,ensemble_entiers);

static int nbre_objets(){ return nbobjets;}


};

Mohamed El Ansari Page 11 sur 34


int ensemble_entiers::nbobjets=0; void operator<(ensemble_entiers
& p, int n){
if (p.nelem<p.dim) p.adr[p.nelem++]=n;
}

void operator>(ensemble_entiers & p, int & n){


if (p.nelem>0) n=p.adr[--p.nelem];
}

ensemble_entiers operator+(ensemble_entiers p,ensemble_entiers q){


int i; ensemble_entiers r(p.dim+q.dim); r.nelem=p.nelem+q.nelem;
for(i=0;i<r.nelem;i++) if (i<p.nelem) r.adr[i]=p.adr[i]; else
r.adr[i]=q.adr[i-p.nelem]; return r; }

main(){

ensemble_entiers t(20);
int val,i;
for(i=0;i<20;i++)
{
cin>>val;
t.empile(val);
}
}

Exercice 2
#include<iostream.h> #define mftion(x) x*(x+1)
inline int iftion(int x){return (x*(x+1));}

main(){
int a=3;
cout<<mftion(a+3)<<endl; // ---> 24
cout<<iftion(a+3)<<endl; // ---> 42
}

• Le résultat correct est celui fournit par la fonction inline iftion.

• Le résultat fournit par la macro-fonction mftion est erroné. Dans l’étape de


précomilation mftion(a+3) sera remplacée par a+3 * (a+3+1) or nous souhaitions
avoir (a+3) * (a+3+1), ce qui donne un résultat incorrect.

Mohamed El Ansari Page 12 sur 34


Département de Mathématiques & Informatique
Faculté des Sciences, Agadir
Epreuve de rattrapage de C++, SMI5-SM5, 2005/2006, Durée: 1h30mn
M. EL ANSARI

Exercice 1
Soit les deux classes suivantes :

class A {
protected :
int i;
public :
A(int k) : i(k) {cout<<"A constructed "<<i<<"\n";}
~A() { cout<<"A deleted\n"; }
};

class B : public A {
private :
int j;
public :
B(int k, int n = 1) : A(k), j(n) { cout<<"B constructed "<<j<<"\n"; }
~B() { cout<<"B deleted\n"; }
};

Que génère le programme suivant ?

void main() {
A *a, *c, *d;
B b(20,30), *e;

a = new A(10);
c = new A(15);
e = new B(2,3);
delete a;
delete e;
}

Exercice 2
Considérons le programme suivant

#include<iostream.h>
#include"Complex.h"

Mohamed El Ansari Page 13 sur 34


1 void main() {
2 Complex i;
3 Complex j(1,-2);
4 Complex k(2.1,3.15);
5 k.afficheComplex();
6 cout<<"Le module de k : "<<k.getModule()<<endl;
7 i = j + k;
8 i.afficheComplex();
9 Complex p = i*j;
10 p.afficheComplex();
11 cout<<"Largument de p : "<<p.getArgument()<<endl;
}

Après exécution le programme ci-dessus génère le résultat suivant:

2.1 + 3.15 i
Le module de k : 3.78583
3.1 + 1.15 i
5.4 + -5.05 i
L’argument de p : -0.751918

Donner les deux fichiers Complex.h et Complex.cpp pour que le programme ci-dessus
donne le résultat attendu.

Indications:

1. Un nombre complexe est défini comme un couple de nombres réels, le premier appelé
partie réelle et le second partie imaginaire. Par exemple 10 + 4 i est un nombre
complexe dont la partie réelle est 10 et la partie imaginaire est 4. Par convention,
on note i le complexe dont la partie réelle est 0 et la partie imaginaire est 1. Sa
particularité est que son carré vaut -1 (i2 = 1).

2. Utiliser uniquement un seul constructeur qui prendra en charge les instructions 2, 3


et 4 (plus d’un seul constructeur la réponse sera considérée fausse).

3. afficheComplex (ligne 5) est une fonction membre de la classe Complex dont le but
l’affichage de l’objet appelant. Lors de sa définition respectez le format d’affichage
mentionné dans l’éxécution.

4. getModule() (ligne 6) est une fonction membre


√ fournissant le module d’un Complex.
Rappelons que le module d’un Complex est re2 + im2 .

5. Pour que le programme acceptera les instructions figurant sur les lignes 7 et 9
vous devez surcharger les opérateurs + et *. Pour cela, définissez les fonctions
correspondantes.

Mohamed El Ansari Page 14 sur 34


6. la ligne 11 contient la fonction getArgument() dont le but est de calculer l’argument
de l’objet appelant. L’argument d’un Complex est tang −1 (im/re). Lors de sa
définition tenez compte du cas ou re =0.

Mohamed El Ansari Page 15 sur 34


Correction
Exercice 1
A constructed 20
B constructed 30
A constructed 10
A constructed 15
A constructed 2
B constructed 3
A deleted
B deleted
A deleted
B deleted
A deleted

Exercice 2
#include<iostream.h>
#include<cmath>
// ------------------------- Complex.h ---------------------

class Complex{
double re, im;

public:
Complex(double vre=0, double vim=0);
~Complex();
void afficheComplex();
double getModule();
double getArgument();
Complex operator+(Complex a);
Complex operator*(Complex a);

};

// ----------------------------- Complex.cpp -------


const double pi=22./7.;

Complex::Complex(double vre, double vim):re(vre),im(vim){}

Complex::~Complex(){} // facultatif

void Complex::afficheComplex(){
cout<<re<<" + "<<im<<" i"<<endl;

Mohamed El Ansari Page 16 sur 34


}

double Complex::getModule(){
return sqrt(re*re+im*im);
}

double Complex::getArgument(){
if (re!=0) return atan(im/re);
if (im >0) return pi/2;
if (im < 0) return -pi/2;
return 0;
}

Complex Complex::operator+(Complex a){


return Complex(a.re+re, a.im+im);
}

Complex Complex::operator*(Complex a){


return Complex(re*a.re-im*a.im,re*a.im+im*a.re);
}

// ---- Programme d’utilisation de la classe Complex ------

void main() {
Complex i;
Complex j(1,-2);
Complex k(2.1,3.15);
k.afficheComplex();
cout<<"Le module de k : "<<k.getModule()<<endl;
i = j + k;
i.afficheComplex();
Complex p = i*j;
p.afficheComplex();
cout<<"Largument de p : "<<p.getArgument()<<endl;
}

Mohamed El Ansari Page 17 sur 34


Département de Mathématiques & Informatique
Faculté des Sciences, Agadir
DS de C++, SM5-SMI5,2006/2007, Durée: 1h
M. El Ansari

Exercice 1
Soient les fonctions suivantes :
int clone(int n){cout << "\nLa fonction I = "; return n*n;}

double clone(double d){cout <<"\nLa fonction II = "; return d*d;}

double clone(int n, double d){cout <<"\nLa fonction III = "; return n*d;}

double clone(double d, int n){cout <<"\nLa fonction IV = "; return d*n;}

double clone(double d, double e=1.0){cout <<"\nLa fonction V = "; return d*e;}

double clone(int n){cout <<"\nLa fonction VI = "; return n*n;}


1. Quelles sont les deux fonctions qui ne peuvent pas être déclarées au sein du même
programme? Dans la suite, on ne conservera que la première des deux dans la liste.
2. Pour chacun des appels suivants, vous direz si le compilateur l’accepte ou pas. Dans
le cas d’une réponse positive, vous indiquerez la fonction appelée ; dans le cas d’une
rponse négative, vous justifierez l’échec.
(a) clone(2);
(b) clone(2.0,3.0);
(c) clone(1.0);
(d) clone(3,4);
(e) clone(’c’);
3. Donnez le résultat d’exécution du programme suivant :

int main() {
cout << clone(3) << endl;
cout << clone(clone(2),3.0) << endl;
}

Exercice 2
Ecrire la macro-fonction (#define) qui calcule la factorielle de n. Puis la fonction inline
qui fait de même.
Montrer et expliquer sur un exemple que l’appel n’est pas réalisé correctement avec la
macro-fonction alors qu’il l’est avec la fonction inline.

Mohamed El Ansari Page 18 sur 34


Exercice 3
On veutécrire une fonction qui fournit la valeur minimale dun tableau unidimensionnel
ainsi que son indice (position de la valeur minimale dans le tableau). La fonction est de
type void. Parmi ses arguments effectifs, il doit figurer un tableau unidimensionnel.

• Ecrire la fonction en utilisant le passage par référence

• Ecrire la fonction en utilisant le passage par adresse

• Ecrire un programme faisant appel à ladite fonction dans les deux cas.

Mohamed El Ansari Page 19 sur 34


Correction
Exercice 1
1. Les fonctions I et VI
(le type de retour n’est pas considéré pour al surcharge, ne fait partie de la signature
des fonctions surchargées). Elimination de la fonction VI du programme

2. Appel des fonctions surchargées:

(a) clone(2); Réponse positive, la fonction appele est I


(b) clone(2.0,3.0); Réponse positive, la fonction appelée est V
(c) clone(1.0); Réponse négative, ambiguüté entre les fonctions II et V
(d) clone(3,4); Réponse négative, ambiguüté entre les fonctions III et IV
(e) clone(’c’); Réponse positive, la fonction appelée est I

3. Le résultat d’exécution:

La fonction I = 9

La fonction I =
La fonction III = 12

Il y a deux lignes vides (la 1ère et la 2ème).


NB. Cheque fois qu’il y a une question dans laquelle il aété demandé de donne
le résultat d’exécution d’un programme, il faut donne ce que l’ordinateur affichera
après l’exeécution en respectant le format d’affichage à savoir les espaces, les retours
à la ligne, ....etc

Exercice 2
• La macro-fonction:

#define factM(n) (((n) > 1) ? (n) * factM((n) - 1) : 1)

• LA fonction inline:

inline unsigned long factI(unsigned long n)


{
return (n > 1) ? n * factI(n - 1) : 1;
}

Un appel à la macro fonction tel que dans le programme suivant:

Mohamed El Ansari Page 20 sur 34


void main()
{
cout << factM(4) << endl;
}

Donne : Erreur à la compilation : ’factM’ : undeclared identifier

Cela est parfaitement normal. En effet, faisons à la main les remplacements effectués par
le prprocesseur (souvenez-vous, c’est du ”copier-coller” !). Nous aurions dans un premier
temps :

cout << (((4) > 1) ? (4) * factM((4) - 1) : 1) << endl;

mais en raison de la récursivité de la macro-fonction il faudrait recommencer...

cout << (((4) > 1) ? (4) * ((((4) - 1) > 1) ?


((4) - 1) * factM(((4) - 1) - 1) : 1) : 1) << endl;

... et cela de manière infinie !!! Ce qui est impossible; compiler un fichier de taille infinie
ne veut rien dire ! Par conséquent, le préprocesseur indique que la macro-fonction factM
n’est jamais entièrement définie et qu’il s’agit donc d’une erreur.

Exercice 3
#include<iostream>
#include<cstdlib>
using namespace std;

// Passage par reference


void min_tab_ref(int T[], int taille, int &min, int &pos)
{
min = T[0]; pos = 0;
for(int i=0;i<taille;i++)
if (T[i]<min)
{
min = T[i];
pos = i;
}
}

// Passage par adresse


void min_tab_adr(int T[], int taille, int *min, int *pos)
{
*min = T[0]; *pos = 0;
for(int i=0;i<taille;i++)
if (T[i]<*min)
{
*min = T[i];

Mohamed El Ansari Page 21 sur 34


*pos = i;
}
}

// Programme test
main()
{
int tab[5] = {2,0,-5,8,41};
int minimum, position;
min_tab_ref(tab, 5,minimum, position);
cout<<"minimum = "<<minimum<<" position = " <<position<<endl;

min_tab_adr(tab, 5,&minimum, &position);


cout<<"minimum = "<<minimum<<" position = " <<position<<endl;
}

// Sortie du programme
minimum = -5 position = 2
minimum = -5 position = 2

Mohamed El Ansari Page 22 sur 34


Département de Mathématiques & Informatique
Faculté des Sciences, Agadir

DS N 2 de C++, SMI5-SM5, 2006/2007, Durée: 1h
M. EL ANSARI

Exercice 1
a) Donner la sortie du programme C++ suivant et commenter en précisant notamment
le nombre d’objets créés et détruits et la nature (plantage ou pas) de la terminaison de
l’exécution.

#include <iostream.h>
class Machin {
public :
int bidule ;
Machin(int b) { cout <<" ++ Machin normal " << endl ; bidule = b; }
~Machin() { cout <<" -- Machin normal " << endl ; }
} ;
class Truc {
public :
Machin * machin ;
Truc(Machin * m) { cout <<" ++ Truc normal " << endl ;
machin = m ;
}
~Truc() { cout << "--Truc normal "<< endl ;
if (machin != NULL) delete machin ;
machin= NULL ; }
} ;
main() {
Machin m(1) ;
Truc x(&m);
Truc y(x);
}

b) Compléter la classe Truc afin de corriger le plontage apparaissant dans la première


exécution (question a)). Donner la sortie du programme C++ et commenter en précisant
le nombre d’objets créés et détruits. Y a plontage? Justifier?
c) On rajoute le constructeur suivant dans la classe Machin.

Machin(Machin & m) {
cout << "++ Machin recopie " << endl ;
bidule = m.bidule ; }

Ré-écrire le constructeur de la classe Truc en utilisant le constructeur de la classe Machin.

Mohamed El Ansari Page 23 sur 34


Exercice 2
Soit le programme C++ suivant:

main(){
POINT a(7,7), b; // creation de deux points a et b
a.affp();cout<<endl; // affichage du point a
SEGMENT s1(1,2,6,9); // creation du segment s1
s1.affs(); cout<<endl; // affichage du segment s1
SEGMENT s2(a,b); // creation du segment s2
s2.affs(); cout<<endl; // affichage du segment s2

// verifier si le point (4,4) appartient au segment s2


if (appartient(POINT(4,4),s2))
cout<<"le point (4,4) appartient au segment s1\n";
else
cout<<"le point (4,4) n’appartient pas au segment s1\n";

cout<<"le nombre de points crees : "<<POINT::nombre_points()<<endl;


cout<<"le nombre de segments crees : "<<SEGMENT::nombre_segments()<<endl;
return 0;
}

Compléter le programme ci-dessus pour qu’il fonctionne correctement. Vous allez définir
les classes POINT et SEGMENT ainsi que les fonctions nécessaires. Un programme complet
donnera la sortie suivante:

point : (7,7)
segment : point : (1,2) point : (6,9)
segment : point : (7,7) point : (0,0)
le point (4,4) appartient au segment s1
le nombre de points crees : 5
le nombre de segments crees : 2

Mohamed El Ansari Page 24 sur 34


Correction
Exercice 1
a) La sortie du programme avant d’atteindre le point de plantage est :

++ Machin normal
++ Truc normal
--Truc normal
-- Machin normal

Détails: L’instruction Machin m(1); génère ++ Machin normal. Création d’un


objet de type Machin
L’instruction Truc x(&m); génère ++ Truc normal. Création d’un objet de type
Truc.
L’instruction Truc y(x) permet de créer un objet de type Truc sans afficher de
message puisqu’il n’y a pas de constructeur de recopie dans la classe Truc. Les
objets x et y partagent l’objet m.
Avant de sortir du programme, il y aura destruction de l’objet y et l’objet pointé
par sa donnée membre. Ce qui donne:
--Truc normal
-- Machin normal
Après, il y aura tentative de destruction de l’objet x. Avant sa destruction, le
compilateur tente de détruire l’espace pointé par le pinteur m de l’objet x. Le
même a été déjà détruit par l’objet y ce qui cause le plontage. 2 objets construits
et 2 objets détruits.

b) Afin de corriger le plantage du programme, il faut dôter la classe Truc d’un


constructeur de recopie.

Truc(Truc & t) {
cout << ++ Truc recopie << endl ;
machin = new Machin(t.machin->bidule) ;
}

La sortie deviendra :

++ Machin normal
++ Truc normal
++ Truc recopie
++ Machin normal
--Truc normal
-- Machin normal
--Truc normal
-- Machin normal

Mohamed El Ansari Page 25 sur 34


Ce résultat est suivi aussi d’un plontage aussi. Tentative de destruction de l’objet
m deux fois. Il est détruit premièrement par l’objet x. Par la suite il y aura echec
de son destruction lors de la deuxième tentative. Objet statique qui sera détruit
automatiquement. Echec.
Pour résoudre le problème, il faut intervenir au niveau du constructeur Truc(Machin
*). Remplacer l’instruction machin = m par machin = new Machin(m->bidule).
Le résultat sera comme suit et sans plantage.

++ Machin normal
++ Truc normal
++ Machin normal
++ Truc recopie
++ Machin normal
--Truc normal
-- Machin normal
--Truc normal
-- Machin normal
-- Machin normal

c) .....

Exercice 2
#include <iostream>
using namespace std;
class SEGMENT;
class POINT{
public:
POINT (int x= 0, int y=0):X(x),Y(y){nbre_points++;}
POINT(const POINT &p):X(p.X), Y(p.Y){}
int Abscisse() const{return X;}
int Ordonnee() const {return Y;}
void affp(){cout<<"point : ("<<X<<","<<Y<<")";}
static int nombre_points(){return nbre_points;}
friend bool appartient(POINT p, SEGMENT s);
private:
int X;
int Y;
static int nbre_points;
};
int POINT::nbre_points = 0;

class SEGMENT{
POINT debut, fin;
static int nbre_segments;
public:
SEGMENT(int x1=0, int y1=0, int x2=0, int

Mohamed El Ansari Page 26 sur 34


y2=0):debut(x1,y1),fin(x2,y2){nbre_segments++;}
SEGMENT(POINT _d, POINT _f):debut(_d),fin(_f){nbre_segments++;}
void affs(){cout<<"segment : ";debut.affp();cout<<" ";fin.affp();}
static int nombre_segments(){return nbre_segments;}

friend bool appartient(POINT p, SEGMENT s);


};

int SEGMENT::nbre_segments = 0;

bool appartient(POINT p, SEGMENT s){


// equation d’une droite y = a * x + b
float a,b; // parametres de la droite
a= (s.fin.Y-s.debut.Y)/(s.fin.X-s.debut.X);
b = s.debut.Y - s.debut.X * a;

if (p.Y == a * p.X + b)
if ((p.X<=s.debut.X && p.X>=s.fin.X) || (p.X>=s.debut.X
&& p.X<=s.fin.X))
return true;
return false;
}

main(){
POINT a(7,7), b; // creation de deux points a et b
a.affp();cout<<endl; // affichage du point a
SEGMENT s1(1,2,6,9); // creation du segment s1
s1.affs(); cout<<endl; // affichage du segment s1
SEGMENT s2(a,b); // creation du segment s2
s2.affs(); cout<<endl; // affichage du segment s2

// verifier si le point (4,4) appartient au segment s2


if (appartient(POINT(4,4),s2))
cout<<"le point (4,4) appartient au segment s1\n";
else
cout<<"le point (4,4) n’appartient pas au segment s1\n";

cout<<"le nombre de points crees : "<<POINT::nombre_points()<<endl;


cout<<"le nombre de segments crees : "<<SEGMENT::nombre_segments()<<endl;
return 0;
}

Mohamed El Ansari Page 27 sur 34


Département de Mathématiques & Informatique
Faculté des Sciences
Examen de C++, SMI5-SM5, 16/01/2008, Durée: 1h30mn
M. EL ANSARI

Exercice 1: (5pts) Surcharge de fonctions


On souhaite donner le même nom à trois fonctions. La première additionne deux entiers
(type int), la deuxième deux réels (type float) et la troisième deux tableaux de dix entiers.
Donner le synopsis de ces fonctions. Que se passe-t-il lorsqu’un appel est fait avec comme
arguments deux short. Pourquoi ? même question si un appel est fait avec un float et
un int? Donner un programme qui fait appel aux trois différentes fonctions.

Exercice 2: (5pts) Différence entre inline et #define


Ecrire la macro-fonction qui calcule factoriel de n. Puis la fonction inline qui fait de
même. Montrer et expliquer sur un exemple que l’appel n’est pas réalisé correctement
avec la macro-fonction alors qu’il l’est avec la fonction inline.

Exercice 3: (10pts) Les classes


Définir une classe Chaine utilisable pour manipuler des chaı̂nes de caractères et dont la
seule donnée membre est un tableau dynamique tab de caractères. On la munira des
méthodes suivantes :

• un constructeur reçevant en paramètre un pointeur sur un caractère (avec "" comme


valeur par défaut), servant à initialiser la donnée membre tab avec une copie de cette
chaı̂ne de caractères,

• un constructeur de copie,

• un destructeur (pourquoi est-il nécessaire!?),

• une méthode length donnant la longueur de la donnée membre tab,

• une méthode concat qui reçoit en paramètre une Chaı̂ne C et retourne une nouvelle
Chaı̂ne dont la donnée membre est la concaténation de tab et de la chaı̂ne de
caractères C,

• une mthode compare permettant de comparer deux chaı̂nes. Elle retourne true (1)
si les deux chaı̂nes sont égales et false (0) le cas contraire.

• une méthode permettant d’afficher tab.

Ecrire un petit programme d’application qui déclare deux instances s1 et s2 de Chaine en


initialisant respectivement leurs contenus à "bon" et "jour", puis qui crée une instance
s3 de Chaine en concaténant s1 et s2 et affiche s3.

Mohamed El Ansari Page 28 sur 34


Correction
Exercice 1
Le synopsis des fonctions.

int add(int a, int b);


float add(float a, float b);

typedef int tab[10];


void add(const tab& a, const tab& b,
tab&res);

inline int add(int a, int b) {


return a + b;
}

inline float add(float a, float b) {


return a + b;
}

void add(const tab& a, const tab& b, tab& res) {


for (int i = 0; i < 10; i++)
res[i] = a[i] + b[i];
}

Que se passe-t-il lorsqu’un appel est fait avec comme arguments deux short.
Pourquoi ?
Un short étant par définition un entier sur 16bit, il est possible de convertir sans perte
d’information un short en int. Par conséquent, lors d’un appel avec comme arguments
deux short, le compilateur va choisir la fonction int add(int, int).
Que se passe-t-il lorsqu’un appel est fait avec un int et un float ?
Confusion entre les 2 premières fonctions et par conséquent le compilateur génère une
erreur au moment de la compilation.
Donner un programme faisant appel aux différentes fonctions.

void main()
{
// addition de 2 entiers (int)
int ia = 1;
int ib = 2;

cout << ia << " + " << ib <<


" = " << add(ia, ib) << endl << endl;

// addition de 2 rels (float)


float fa = 1.3f;

Mohamed El Ansari Page 29 sur 34


float fb = 2.8f;
cout << fa << " + " << fb <<
" = " << add(fa, fb) << endl << endl;

// addition de 2 tableaux de 10 entiers


tab ta = { 1, 3, 7, 5, 2, 8, 2, 0, 3, 6 };
tab tb = { 4, 2, 6, 1, 8, 1, 3, 7, 1, 2 };

tab tr;
add(ta, tb, tr);

cout << "Addition de deux tableaux" << endl;


for (int i = 0; i < TAB_LENGTH; i++)
{
cout << "\t" << ta[i] << " + " << tb[i] <<
" = " << tr[i] << endl;
}
cout << endl;

...

Exercice 2
Même solution que celle donnée en exercice 2 page 20.

Exercice 3
Même solution que celle donnée en exercice 3 page 7.

Mohamed El Ansari Page 30 sur 34


Département de Mathématiques & Informatique
Université Ibn Zouhr, Faculté des Sciences
DS/Session Normale/C++/SMI5-SM5, 2009/2010, Durée: 1h30mn
Pr. M. EL ANSARI

Exercice 1: (15pts)
Définir une classe Chaine utilisable pour manipuler des chaı̂nes de caractères et dont la
seule donnée membre est un tableau dynamique tab de caractères. On la munira des
méthodes suivantes :

1. un constructeur reçevant en paramètre un pointeur sur un caractère (avec "" comme


valeur par défaut), servant à initialiser la donnée membre tab avec une copie de cette
chaı̂ne de caractères,

2. un constructeur de recopie,

3. un destructeur, pourquoi est-il nécessaire!?,

4. une méthode length donnant la longueur de la donnée membre tab,

5. une méthode reverse permettant de reverser la donnée membre tab, par exemple,
la chaı̂ne maison deviendra nosiam,

6. surcharge de l’opérateur + afin qu’on puisse l’utiliser pour la concaténation de deux


instances de la classe chaine.
Exemple: Les instructions chaine ch1("Mohamed "), ch2("EL ANSARI"), ch3;
ch3 = ch1+ch2;
permettront de mettre Mohamed EL ANSARI dans l’objet ch3.
Donner la fonction de surcharge correspondante.

7. surcharge de l’opérateur >>. L’instruction cin>>ch1; permet de modifier le contenu


de l’objet ch1.

8. surcharge de l’opérateur <<. L’instruction cout<<ch2; donne EL ANSARI après son


exécution.

9. une méthode compare permettant de comparer deux chaı̂nes. Elle retourne true (1)
si les deux chaı̂nes sont égales et false (0) le cas contraire.

10. une méthode affiche permettant d’afficher un objet de la classe chaine.

11. une fonction lengthmax permettant d’obtenir parmi deux chaı̂nes, celle qui a la plus
grande longueur.

Ecrire un petit programme d’application qui déclare des instances de la classe Chaine
sur lesquelles vous allez appliquer les différentes fonctions définies ci-dessus (fonctions
membres et fonctions surchargées).

Mohamed El Ansari Page 31 sur 34


Exercice 2: (5pts)
Donner le résultat d’exécution du programme ci-dessous. Attention: il faut respecter le
format d’affichage.

#include<iostream>
using namespace std;
int x = 6;
int h(int & x){x = 2*x; return x;}
int g(int m){return x++;}
int & f(int &x){x+=::x; return x;}
int main()
{
int x = -1;
f(::x) = h(x);
cout<<f(x)<<" "<<g(x)<<" "<<h(x)<<" "<<x<<"
"<<::x<<endl;
f(::x) = g(x);
cout<<f(x)<<" "<<g(x)<<" "<<h(x)<<" "<<x<<"
"<<::x<<endl;
return 0;
}

Mohamed El Ansari Page 32 sur 34


Correction
Exercice 1
#include<iostream>
using namespace std;

class chaine{
char *tab;
public:
int length(){return strlen(tab);}

chaine(char*_tab = ""){
tab = new char[strlen(_tab)+1];
strcpy(tab,_tab);
}
chaine(chaine & t){
tab = new char[strlen(t.tab)+1];
strcpy(tab, t.tab);
}
~chaine(){delete [] tab;}

void affiche(){cout<<tab;}
void reverse(){
int taille = strlen(tab);
char c;
for(int i=0;i<taille/2;i++)
{
c=tab[i];
tab[i]=tab[taille-1-i];
tab[taille-1-i] = c;
}
}
bool compare(chaine & c){
int i, t1=strlen(tab), t2=c.length(), min;
min = t1<t2? t1 : t2;
if (t1 != t2) return 0;
else for(i=0;i<min;i++) if (tab[i] != c.tab[i]) return 0;
return 1;
}
chaine lengthmax(chaine c){
if (strlen(tab)>c.length()) return *this; else return c;
}
friend chaine operator+(chaine c1, chaine c2);
friend istream & operator>>(istream & i, chaine & c);
friend ostream & operator<<(ostream & o, chaine &c);

Mohamed El Ansari Page 33 sur 34


};
chaine operator+(chaine c1, chaine c2){
int t1=c1.length(), t2 = c2.length();
char *c = new char[t1+t2+1];
int i;
for (i=0;i<t1;i++) c[i] = c1.tab[i];
for(i=t1;i<t1+t2;i++)
c[i] = c2.tab[i-t1];
c[i] = ’\0’;
return chaine(c);
}

istream & operator>>(istream & i, chaine & c){


cout<<"Donner une chaine :";
i>>c.tab;
return i;
}
ostream & operator<<(ostream & o, chaine &c){
o<<c.tab;
return o;
}

int main()
{
chaine ch1("Mohamed "), ch4("EL ANSARI");
chaine ch2(ch1);
ch1.affiche();cout<<endl;
ch2.affiche();cout<<endl;
cout<<ch1.length();cout<<endl;
ch2.reverse(); ch2.affiche(); cout<<endl;
chaine ch3=ch1+ch4;
ch3.affiche(); cout<<endl;
cin>>ch2;
ch2.affiche(); cout<<endl;
cout<<ch2<<endl;
cout<<ch1.compare(ch2)<<endl;
cout<<ch1.lengthmax(ch4)<<endl;
return 0;
}

Exercice 2
-5 -2 -4 -2 -2
-10 -1 -10 -5 -1

Mohamed El Ansari Page 34 sur 34

Vous aimerez peut-être aussi