float P; int Nb; cout << "prix unitaire ? "; cin >> P; cout << "Nombre ? "; cin >> Nb; cout.precision(2); //manipulateur (fonction membre)de cout : tous les //flottants QUI SUIVENT seront affichés avec // 2 chiffres après la virgule cout << "prix total : " << P*Nb << "F \n";L'avantage de ces fonctions est qu'elles peuvent être plus facilement surchargées que printf et scanf (par exemple étendues aux tableaux). Les flux fstream possèdent les mêmes fonctionnalités pour les fichiers (je ne détaille pas).
const type var=valeur;contrairement au #define, permet une analyse syntaxique (on garde les define pour les "réécritures" et compilations conditionnelles).
void echange(int &a, int &b) {int z=a;a=b;b=z;} int X,Y;echange(X,Y);
class MaClasse {déclaration données et méthodes } MonInstance;
Ne pas oublier le ; final même quand on ne déclare pas d'instance ici (en général les classes sont globales, les variables devraient plutôt être locales). En fait les mots clef struct et union permettent également la déclaration de méthodes en plus de données, simplement elles sont par défaut publiques (public) (accessibles aux autres classes) alors que pour une classe elles sont par défaut privées (private).
class Point { int X;intY; //les données int GetX(void) {return X;} // déclaration "interne" ou "inline" int GetY(void); // déclaration externe Point (int NewX=0, int NewY=0) {X=NewX;Y=NewY;} //déclaration //interne du constructeur, avec initialisation par défaut }; int Point::GetY(void) {return Y;} //déclaration "externe", il faut préciser //à quelle classe elle se rapporte ici POINT. //dans la réalité j'aurai plutot utilisé une déclaration internesi je déclare :
Point P(5,10); //appel automatique du constructeur à ladéclaration int coordX;je peux par exemple appeler la fonction (attention, pas n'importe où, voir paragraphe suivant) :
coordX=P.GetX();
class Point { int X;intY; //privé par défaut public : // tout ce qui suit est public int GetX(void) {return X;} // ceci permet d'accéder aux //infos sans savoir comment elles ont été stockées int GetY(void) {return Y;} Point (int NewX, int NewY) {X=NewX;Y=NewY;} };On peut utiliser les 3 accès, autant de fois que l'on veut et dans n'importe que ordre. L'accès qui s'applique est le dernier spécifié (ou celui par défaut, private pour class et public pour struct).
class Point { protected: //accessible uniquement par héritage int X;intY; public : // accessible partout int GetX(void) {return X;} int GetY(void) {return Y;} Point (int NewX=0, intNewY=0) {X=NewX;Y=NewY;} }; class Pixel : public Point //dérive de point, { protected: int couleur; public : Pixel (int nx,int ny,int coul=0); void allume(void); void allume(int couleur); //surcharge : on peut allumer avec une autre couleur void eteind(void); };Les accès dérivés sont le plus restrictif entre celui défini dans la classe de base et celui précisé lors de la dérivation (ici dérivation publique, les accès restent inchangés sauf pour les privés qui sont inaccessibles).
Pixel::Pixel(int nx,int ny,int coul):Point(nx,ny) // je précise la //liste (séparée par des virgules) des constructeurs //(sinon val par défaut), je n'ai plus qu'à construire les //ajouts par rapport à la classe de base {couleur=coul;} void Pixel::allume(void) {g_pixel(X,Y,couleur);} //g_pixel : une fonction qui allume un pixel à l'écran void Pixel::allume(int coul) {g_pixel(X,Y,couleur=coul);} void Pixel::eteind(void) {allume(0);}On pourrait maintenant définir une classe segment contenant un pixel et un point (la couleur n'a besoin d'être stockée qu'une fois). On redéfinirait des méthodes de même nom : Segment::allume...
Pixel *ptrPixel = new Pixel(100,100,1); // construction explicite ptrPixel->allume(); //utilisation delete ptrPixel; //destruction, le destructeur par défaut est souvent suffisantSi l'on veut définir explicitement le destructeur d'une classe (pour fermer un fichier par exemple), on utilise le nom de la classe précédé de ~ :
Point::~Point() {...}
Point operator+ (Point &P1, Point &P2) { Point res(P1.GetX()+P2.GetX(),P1.GetY()+P2.GetY(),P1); return res;}On peut aussi surcharger << (pour cout) :
ostream& operator << (ostream& flux, Point& P) { flux << "[" << P.GetX() << "," << P.GetY() << "]"; return flux; }Ces deux surcharges sont globales. Mais on peut également les définir comme fonctions membres :
class Point { ..... Point operator + (Point &P); Point operator = (Point &P); }; Point::Point::operator + (Point & P) {Point r;r.X=this->X+P.X;r.Y=this->Y+P.Y;return r;} void main(void) { Point A,B,C; A=B; //appelle A.operator=(B) B+C; //appelle A.operator+(B) A=B+C; //marchera aussi, mais A=B=C je n'en suis pas sur }
class A {...}; class B : virtual public A {...}; class C : virtual public A {...}; class D : public C, public D {...};Le constructeur de D appellera une seule fois celui de A
#include <iostream.h> #include "graphiq0.cpp" // petite biblio graphique. contient g_init, // g_fin, g_pixel, g_ligne (voir plus loin) class Point { protected: //accessible uniquement par héritage int X;int Y; public : // accessible partout int GetX(void) {return X;} //hors héritage on ne peut que lire, //pas écrire int GetY(void) {return Y;} Point (int NewX=0, int NewY=0) {X=NewX;Y=NewY;} }; //On peut surcharger << (pour cout) : marche pour le point et ses héritiers : ostream& operator << (ostream& flux, Point& P) { flux << "[" << P.GetX() << "," << P.GetY() << "]"; return flux; } class Pixel : public Point //dérive de point { protected: int couleur; public : Pixel (int nx=0,int ny=0,int coul=0); virtual void allume(void); virtual void allume(int couleur); //surcharge : on peut allumer avec une autre couleur void eteind(void); // héritable dynamiquement void ajoute(int plusx=1,int plusy=1); void deplace(int plusx=1,int plusy=1);// héritable dynamiquement int GetCouleur(void); }; Pixel::Pixel(int nx,int ny,int coul):Point(nx,ny) //je passe ainsi les // arguments au constructeur de Point (sinon il prend // celui par défaut, cad sans arguments {couleur=coul;} void Pixel::allume(void) {g_pixel(X,Y,couleur);} void Pixel::allume(int coul) {g_pixel(X,Y,couleur=coul);} void Pixel::eteind(void) {allume(0);} //allume est virtuelle, toute classe dérivée //possédant allume possèdera automatiquement éteint void Pixel::ajoute(int plusx,int plusy) {X+=plusx;Y+=plusy;} void Pixel::deplace(int plusx,int plusy) { int OldCol=couleur;eteind();couleur=OldCol; ajoute(plusx,plusy);allume();} int Pixel::GetCouleur(void) {return couleur;} class Segment : public Pixel { protected : int LX;int LY; public : Segment (int x0=0,int y0=0,int lx=0,int ly=0,int coul=1); void allume(void); void allume(int couleur); //le reste est hérité }; Segment::Segment(int x0,int y0,int lx,int ly,int coul):Pixel(x0,y0,coul) {LX=lx;LY=ly;} void Segment::allume(void) {g_ligne(X,Y,X+LX,Y+LY,couleur);} void Segment::allume(int coul) {g_ligne(X,Y,X+LX,Y+LY,couleur=coul);} class Rectangle : public Pixel { protected : int LX;int LY; public : Rectangle (int x0=0,int y0=0,int lx=0,int ly=0,int coul=1); void allume(void); void allume(int couleur); }; Rectangle::Rectangle(int x0,int y0,int lx,int ly,int coul):Pixel(x0,y0,coul) {LX=lx;LY=ly;} void Rectangle::allume(void) { g_ligne(X,Y,X+LX,Y,couleur); g_ligne(X+LX,Y,X+LX,Y+LY,couleur); g_ligne(X+LX,Y+LY,X,Y+LY,couleur); g_ligne(X,Y+LY,X,Y,couleur); } void Rectangle::allume(int coul) {couleur=coul;this->allume();} //utilisons le signe + pour additionner deux objets quels qu'ils soient: template <class T> //T est un type de classe "variable" T operator+ (T &P1,Point &P2) {T res(P1.GetX()+P2.GetX(),P1.GetY()+P2.GetY(),P1);return res;} // ce qui ne marche pas pour les types autres que point : le constructeur // prend les autres arguments par défaut (longueur, couleur) void main(void) { g_init(); Pixel *ptrPixel = new Pixel(100,100,1); ptrPixel->allume(); //utilisation cout << *ptrPixel << ':' << ptrPixel->GetCouleur()<< '\n'; delete ptrPixel; //destruction, le destructeur par défaut est souvent suffisant Segment s(50,50,100,0,10); s.allume(); Rectangle r(150,150,100,100,4); r.allume(); cin.get(); //équivalent du getch Point decal(-25,25); cout << (s+decal) << endl; (r+decal).allume(); s.deplace(0,100); r.deplace(0,100); cout << r << endl; //endl envoie un \n cin.get(); g_fin(); }
/* fichier inclus pour INTRO.CPP, version Turbo C 3.0 P.Trau 22/2/97 */ /* bibliothèque graphique minimale . Ce fichier contient les fonctions qu'il faudra réécrire si l'on change de compilateur. Il faut savoir : - passer en mode graphique : g_init (sauf si vous y êtes déjà) - quitter le mode graphique : g_fin - allumer un point : g_pixel - à la rigueur tracer une ligne : g_ligne (ou le laisser tel quel, il n'utilise que g_pixel) */ #include <graphics.h> #define abs(X) ((X>0)?(X):(-(X))) void g_init(void) { int gdriver = DETECT, gmode, errorcode; initgraph(&gdriver, &gmode, ""); errorcode = graphresult(); if (errorcode != grOk) #ifdef __cplusplus cout << "g_erreur: " << grapherrormsg(errorcode) <<"\n"; #else printf("g_erreur: %s\n", grapherrormsg(errorcode)); #endif setcolor(getmaxcolor()); } void g_fin(void) {closegraph();} void g_pixel(int x,int y,int color) {putpixel(x,y,color);} void g_ligne(int xd,int yd,int xf,int yf,int color) { int somme,pasx,pasy,deltax,deltay; deltax=abs(xf-xd);deltay=abs(yf-yd); pasx=(xd<xf)?1:-1; pasy=(yd<yf)?1:-1; g_pixel(xd,yd,color); if (deltax>deltay) /* ils sont déjà positifs */ { somme=deltax/2; while(xd!=xf) { xd+=pasx; somme+=deltay; if(somme>=deltax) {somme-=deltax;yd+=pasy;} g_pixel(xd,yd,color); } } else { somme=deltay/2; while(yd!=yf) { yd+=pasy; somme+=deltax; if(somme>=deltay) {somme-=deltay;xd+=pasx;} g_pixel(xd,yd,color); } } }