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 lib1namespace lib2
{
class string{};
} // namespace lib2lib1/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