On Github ghlecl / BaseProgCxx
© 2015 Ghyslain Leclerc, CHUQ-UL
Instructions lisibles par un humain
Instructions lisibles par un processeur
Facteurs à considérer → choix d'un langage :
↑
↓
C++
↓
↑
↑
~
↑
Souvent en conflit
C++
Selon Wikipedia :
Clinique
À rechercher en écrivant du code :
Autant que possible...
var_type var_name; int age; double sales_tax; char my_char;
int a average = ( 5 + 7 ) / 2 multi_strings = tokenize( single_string )
Combinaisons de:
qui sont interprétés selon les règles de précédences d'un langage et qui redonnent une valeur (qu'elle soit utilisée ou pas).
int a (aucune sous-expression) average = ( 5 + 7 ) / 2 ( 5 + 7 -> "sous-expression" 1 ) ( résultat précédent / 2 -> "sous-expression" 2 ) ( etc. )
Une expression peut être composée d'expressions.
Expression Instruction ---------- ----------- int a int a; ( 5 + 7 ) / 2 ( 5 + 7 ) / 2;
Exemple de C++
begin program statement 1 statement 2 statement 3 ... statement n end program
begin function1( no_entrants ) statement f1_1 statement f1_2 return value_f1 end function1 begin function2( 1_entrant ) value_f2 = 1_entrant + 5 return value_f2 end function2 begin program var1 = call function1() call function2( var1 ) end program
Concept de scope expliqué plus loin
begin function1 begin procedure1 statement f1_1 statement m1_1 statement f1_2 // no return statement return value_f1 end procedure1 end function1
Selon Wikipedia :
int varGlobale; namespace ns { int varLocale_Namespace; } void fn( int input ) { int varLocale_Fonction; if( true ) { int varLocale_If; } // varLocale_If non disponible ici // varLocale_Namespace non disponible sauf si qualifiée (ns::varLocale_Namespace) } // varLocale_Fonction non disponible ici...
[Pseudo code, aucun langage] 1 print "Combien de bonjour vous voulez (1 ou 2) ?" 2 3 lire valeurLue 4 5 if valeurLue == 1: 6 goto 9 7 8 print "Bonjour" 9 print "Bonjour" 10
[Pseudo code, aucun langage] 1 print "Combien de bonjour vous voulez (1 ou 2) ?" 2 3 lire valeurLue 4 5 int compteur = 0 6 for( compteur != valeurLue, increment compteur ) 7 { 8 print "Bonjour" 9 } 10
=========== do ... while bool_exp =========== while bool_exp do ... =========== if bool_exp ... else if bool_exp ... else ... =========== for( pre-processing ; bool_exp ; post-processing ) ...
int a int b ... if ( a + 3 > b - 6 ) print "vrai"
Expression seulement, pas instruction.
Forme de programmation où l'on décrit les opérations en séquences d'instructions exécutées par l'ordinateur pour modifier l'état du programme.
std::string myStrgVar; std::string mySTRGVar; // OK, not the same
int a = 8; int a = 8; // exactly the same void myFn( int firstIn double secondIn );
if { // statements }
int const a;
type
modificateur(s)
nom
int* a; int *a;
Variable de type pointeur:
Variable de type référence:
int& b = a; int &b = a; // illegal
int main( int argc, char* argv[] ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int fn1() { SecondType var1; SecondType* var2; var2 = new SecondType; }
int fn2() { ThirdType var1; int var2; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int fn1() { SecondType var1; SecondType* var2; var2 = new SecondType; }
int fn1() { SecondType var1; SecondType* var2; var2 = new SecondType; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int fn1() { SecondType var1; SecondType* var2; var2 = new SecondType; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int fn2() { ThirdType var1; int var2; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int fn2() { ThirdType var1; int var2; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int main( ... ) { int var1; FirstType* var2; var2 = new FirstType; fn1() fn2() delete var2; return SUCCESS; }
int a( 4 ); // a is on the stack int& b( a ); // b is on the stack because it's a int* c( new int ); // c is on the stack. *c = 4; // what c points to is on the heap // so 0xf6a340bc is on the stack // and 4 is on the heap int* d( &a ) // d is on the stack and points to // the stack
int a( 4 ); // equivalent to int a = 4; int& b = a; int* c = new int; *c = 4; printf( "%i", a ); // outputs 4 to the screen printf( "%i", b ); // outputs 4 to the screen printf( "%i", c ); // outputs address of c to the screen printf( "%i", *c ); // outputs 4 to the screen
Variable et référence:
Pointeur
Compilation
Communication
Dis au compilateur de ne pas permettre de modification de la variable.
Promet à l'utilisateur du code que la variable ne changera pas après l'appel de fonction.
Erreurs de compilation
Lire de droite à gauche
//*** Read from right to left *** int const* a; // pointer to const int // pointer can change, pointee can't int* const a; // const pointer to int // pointer can't change, pointee can int const* const a; // const pointer to const int // pointer and pointee can't change
double convertToDbl( std::string const& strg );
sortie
entrant(s)
nom
#include <string> double convertToDbl( std::string const& strg ) { int a; // accessible only in the function body strg = "nouvelle valeur"; // forbidden because of the const double convertedVal = atod( strg.c_str() ); return convertedVal; }
Dans le scope de la fonction, seules les variables globales, définies localement et d'entrées sont disponibles.
double convertToDbl( std::string const& strg );
Les entrants d'une fonction peuvent l`être de quelques façons différentes :
En réalité, tout est passé par copie...
double convertToDbl( std::string strg );
double convertToDbl( std::string& strg );
double convertToDbl( std::string* strg );
Si fonction...
void fn1( std::string& willBeModified ) {} std::vector< double > fn2( std::string const& willNotBeModified ) {}
struct Staff { int id char* lastName; char* firstName; char* jobTitle; };
void fn_A( int staffID, char* lastName, char* firstName, char* jobTitle ); void fn_B( Staff& staff );
#include <string> // (1) #include <iostream> // (1) int a; // (2) int* b; // (3) int& c; // (4) double fn( std::string const& nbStrg ); // (5) double fn( std::string const& nbStrg ) { double converted; ... // (6) return converted; }
Forme de programmation où l'on génère des objets (données + routines) pour représenter les concept du programme.
L'interaction entre ces objets, via leurs relations, permet de concevoir et réaliser les fonctionnalités attendues et de résoudre le ou les problèmes.
struct Staff { int id char* lastName; char* firstName; char* jobTitle; }; struct StaffVector { Staff* allStaff[]; int nbInVec; };
void addStaff( StaffVector& vec, Staff const& staffToAdd ) { // Add staffToAdd ++(vec.nbInVec); } void removeStaff( StaffVector& staffVec, int idx ) { // Remove staff at index idx --(vec.nbInVec); }
void addStaff( StaffVector& vec, Staff const& staffToAdd ) { // Add staffToAdd ++(vec.nbInVec); } void removeStaff_Better( StaffVector& vec, int idx ) { // Remove staff at index idx // Oups, forgot to decrement }
Cohérence de la structure StaffVector est perdue
struct Staff { ... }; class StaffVector { public: add( Staff const& staff ); remove( int idx ); private: Staff* allStaff_[]; int nbInVec_; };
class StaffVector { public: add( Staff const& staff ); remove( int idx ); int myMemberPublicData; private: Staff* allStaff_[]; int nbInVec_; };
void fn1( Staff& staff ) { staff.nbInVec_ = 5; // compile no, priv. and non-member fn staff.myMemberPublicData = 8; // compile ok, bad practice }
class StaffVector { public: add( Staff const& staff ); remove( int idx ); private: Staff* allStaff_[]; int nbInVec_; };
struct StaffVector { Staff* allStaff[]; int nbInVec; };
class StaffVector { public: add( Staff const& staff ); remove( int idx ); private: Staff* allStaff_[]; int nbInVec_; };
struct StaffVector { public: add( Staff const& staff ); remove( int idx ); private: Staff* allStaff_[]; int nbInVec_; };
Équivalent, sauf pour l'accès par défaut, c.-à-d. sans spécification.
struct StaffVector { add( Staff const& staff ); remove( int idx ); Staff* allStaff_[]; int nbInVec_; };
class StaffVector { public: add( Staff const& staff ); remove( int idx ); Staff* allStaff_[]; int nbInVec_; };
struct StaffVector { private: add( Staff const& staff ); remove( int idx ); Staff* allStaff_[]; int nbInVec_; };
class StaffVector { add( Staff const& staff ); remove( int idx ); Staff* allStaff_[]; int nbInVec_; };
=
=
Recette pour créer un type d'objet.
Résultat de l'application de la recette pour créer un objet spécifique.
#include <string> class Staff { int id_; std::string lastName_; std::string firstName_; std::string jobTitle_; };
#include "Staff.h" // Instances // Object 1 Staff staff1( 0, "Leclerc", "Ghyslain", "Phys" ); // Object 2 Staff staff2( 1, "Brouard", "Lucie", "Tech" );
Staff.h
Privée par défaut
class StaffVector { public: void remove( int idx ); int size() const; private: Staff* allStaff_[]; int nbInVec_; };
Indique si une fonction membre peut ou pas être utilisée sur un objet const.
StaffVector staffVec1; StaffVector const staffVec2; staffVec1.size() // Compile ok, non-const object, const fn staffVec2.size() // Compile ok, const object, const fn staffVec1.remove() // Compile ok, non-const object, non-const fn staffVec2.remove() // Compile no, const object, non-const fn
#include <string> class Staff { public: Staff(); // Default ctor : called when no args Staff( std::string lastName, std::string firstName ); // Nondescript ctor Staff( Staff const& staff ); // Copy ctor : creates a duplicate private: int id_; std::string lastName_; std::string firstName_; std::string jobTitle_; };
#include <string> class Staff { public: Staff(); Staff( Staff const& staff ); ~Staff(); // dtor private: int id_; std::string lastName_; std::string firstName_; std::string jobTitle_; };
#include <string> class Staff { public: int id() { return id_; } // Getter, access value of id_ void setId( int newId ) { id_ = newId; } // Setter, change value of id_ private: int id_; std::string lastName_; std::string firstName_; std::string jobTitle_; };
#include <string> class Staff { public: Staff& operator=( Staff const& staff ); // Assignment operator void operator++() { jobTitle_ = "Président"; } // increment operator private: int id_; std::string lastName_; std::string firstName_; std::string jobTitle_; };
#include <string> class Staff { public: // better than increment operator void promote() { jobTitle_ = "Président"; } private: int id_; std::string lastName_; std::string firstName_; std::string jobTitle_; void myPrivateFunc_(); };
#include <string> class Staff { ... }; void fn( Staff& staff );
// Let a class Staff exist and be defined in Staff.h #include "Staff.h" Staff staff1; // call ctor by default Staff staff2(); // call ctor by default Staff* staff3 = new Staff(); // call ctor by default staff1.fn1(); // call fn1 on object staff1 staff3->fn1(); // call fn1 on object staff3 fn2( staff2 ); // call non-member function fn2 on staff2 -(*staff3); // call unary operator - on staff3 staff1 + staff2; // call binary operator +
Le compilateur génère quelques fonctions par défaut si non écrites [C++03] :
class A { A(); A( A const& a ); A& operator=( A const& a ); ~A(); };
class A { A() = default; A( A const& a ) = default; A& operator=( A const& a ) = default; ~A() = default; };
Celui auquel le mot fait généralement référence
int fn1( int input1 ); int fn1( double input1 ); int fn1( std::string input1 ); // illegal, no overloading on return value double fn1( int input1 );
class ObjectThanCanFly { virtual void fly(); virtual double currentAltitude() const; }; class Bird : public ObjectThanCanFly { // gets functions fly() and currentAltitude() whitout defining them }; class Plane : public ObjectThanCanFly { // gets functions fly() and currentAltitude() whitout defining them };
void make_fly( ObjectThatCanFly& obj ) { obj.fly(); } int main( int argc, char* argv[] ) { Bird theBird; Plane thePlane; make_fly( theBird ); make_fly( thePlane ); }
Significatif ? Si appellé 1 000 000 de fois, peut-être. Vérifier au besoin.
template< typename T > void swap( T& left, T& right ) { T temp( left ); left = right; right = temp; } int a( 6 ), b( 7 ); double c( 4.5 ), d( -5.7 ); swap( a, b ); // create with T == int swap( c, d ); // create with T == double
void swap( int& left, int& right ) { int temp( left ); left = right; right = temp; }
void swap( double& left, double& right ) { double temp( left ); left = right; right = temp; }
Définition d'algorithmes identiques opérant sur des données de types différents spécifiés plus ultérieurement.
#include "lib1/string.h" #include "lib2/string.h" void myCoolFunction() { string nameOfUser( "" ); // which string -> name clash }
#include "lib1/string.h" #include "lib2/string.h" void myCoolFunction() { lib1::string nameOfUser( "" ); // using string class of lib1 }
main.cxx
namespace lib1 { class string{}; } // namespace lib1
namespace lib2 { class string{}; } // namespace lib2
lib1/string.h
lib2/string.h
namespace blabala { void fn1(); namespace inner // can be nested { void fn2(); } // namespace inner } // namespace blabala namespace blabala // are additive (as opposed to classes and structs) { void fn3(); } // namespace blabala
// Different calls for fn1. ::fn1(); // At global scope. If not found, error. ::std::fn1(); // From the namespace std at the global scope. If not found, error. std::fn1(); // From the namespace std at current scope. // If not found, try to find namespace std in global scope // and fn1 in that one. // If not found, error.
computer > g++ -o nom_executable main.cpp
Fichiers que l'on écrit
Compilateur
Options du compilateur
computer > cl.exe /EHsc main.cxx
Deux étapes :
C'est ici que l'on code
computer > g++ -c file1.cxx computer > g++ -c file2.cxx ... computer > g++ -c main.cxx computer > g++ -o nom_executable file1.o file2.o ... main.o
Raccourci pratique pour appeler le compilateur et l'éditeur de lien