Différences entre les versions de « C++ »
toros>WikiAdmin |
m (1 version importée) |
(Une version intermédiaire par un autre utilisateur non affichée) | |
(Aucune différence)
|
Version actuelle datée du 9 février 2023 à 12:51
1 Références
2 Liens externes
- ★ Complete C++ language tutorial
- from its basics up to the newest features introduced by C++11
- The cplusplus.com www.cplusplus.com
- Cours de C/C++ de Christian Casteyde (2003)
- Ce livre est un cours de C et de C++. Il s'adresse aux personnes qui ont déjà quelques notions de programmation dans un langage quelconque. Les connaissances requises ne sont pas très élevées cependant : il n'est pas nécessaire d'avoir fait de grands programmes pour lire ce document. Il suffit d'avoir vu ce qu'est un programme et compris les grands principes de la programmation.
- [2]
- ★★★★ Liste complète par catégorie et besoin des livres sur le langage C++
- ★★★ C++ reference C++98, C++03, C++11, C++14, C++17, C++20, C++23 ; Compiler support C++11, C++14, C++17, C++20, C++23
- ★★★ C++ Standards Support in GCC
- ★★★ Nouvelles fonctionnalités du C++11 (developpez.com)
- JTC1/SC22/WG21 - The C++ Standards Committee - ISOCPP
- OSDL (free portable high-level open-source library for multimedia and game programming)
- Ceylan project
- Cours de C++
- http://www.cplusplus.com
- C++ (http://www.allprog.com/CPlusPlus/index.htm)
- Todd Veldhuizen: Papers, articles, talks...
- blitz++
- C++ Portability Guide
- GCC online documentation
- Le compilateur C++ KAI
- GNU Make
- Techniques for Scientific C++
- IT++
- FFTw (the Fastest Fourier Transform in the West.)
- IBM XL C/C++ V8.0 for Linux, Getting started
- www.progmatique.fr (Rubrique : Cpp)
- www.cppreference.com/
- H-Deb
3 Voir aussi
4 La fonction main
int main(void);
int main();
int main(int argc, char *argv[]);
5 La gestion du temps
5.1 Attendre
5.1.1 sleep
#include <time.h>
void sleep( time_t nb_sec )
{
time_t limit, top;
time(&top);
limit = top + nb_sec ;
while (top < limit)
{
time(&top);
}
};
5.1.2 Exemple
#include <time.h>
#include <stdio.h>
void sleep( time_t nb_sec )
{
time_t limit, top;
time(&top);
limit = top + nb_sec ;
while (top < limit)
{
time(&top);
}
};
int main( int argc, char * argv[] )
{
time_t start, stop;
time(&start);
sleep( 5 ) ;
time(&stop);
printf("start : %ld\n",start );
printf("stop : %ld\n",stop );
printf("in seconds: %f\n",difftime(stop,start));
}
Ce qui donne :
start : 1253277063
stop : 1253277068
in seconds: 5.000000
6 Les commandes du pré-processeur
6.1 #, ##
manipulate strings
Exemple :
#define toxmlSart( tag ) tag##_index++ ; file << "<" << #tag << " id='" << tag##_index <<"' >" << std::endl ;
D'autres exemples :
#define toxmltag( var ) file << " <d id='" << #var << "' val='" << var << "'/>" << std::endl ;
#define toxmlSart( tag ) tag##_index++ ; file << "<" << #tag << " id='" << tag##_index <<"' >" << std::endl ;
#define toxmlSartname( tag, name ) tag##_index++ ; file << "<" << #tag << " id='" << name <<"' >" << std::endl ;
#define toxmlSartE( tag ) file << "</" << #tag << ">" << std::endl ;
6.2 traces écran
#include <fstream>
#ifdef UTILITIES_TRACE
#define MYMSG_INFO " :" <<__FILE__ <<" ["<<__LINE__<<"]"
#define MYTRACE_BEGIN std::cout <<
#define MYTRACE_END << MYMSG_INFO
#define mytr( flow ) MYTRACE_BEGIN flow MYTRACE_END
#define mytrln( flow ) MYTRACE_BEGIN flow MYTRACE_END << std::endl
#define mytrBeginln( flow ) MYTRACE_BEGIN "Begin " << flow MYTRACE_END << "..." << std::endl
#define mytrEndln( flow ) MYTRACE_BEGIN "End " << flow MYTRACE_END << std::endl
#define myscrute(var) mytr( #var << "=" << var )
#define myscruteln(var) mytrln( #var << "=" << var )
#else
#define mytr( flow )
#define mytrln( flow )
#define mytrBeginln( flow )
#define mytrEndln( flow )
#define myscrute(var)
#define myscruteln(var)
#endif
6.3 traces fichier
const char* tracePath = "/home/C07138/logs/gabv2/" ;
#define UTILITIES_TRACE
#include <libgen.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <iomanip>
const std::string currentDateTime() {
time_t now = time(0);
struct tm tstruct;
char buf[80];
tstruct = *localtime(&now);
strftime(buf, sizeof(buf), "%Y-%m-%d_%H-%M-%S", &tstruct);
return buf;
}
const std::string currentDateTimeMs() {
struct timeb tstructMs;
ftime(&tstructMs);
struct tm tstruct;
char buf[80];
tstruct = *localtime(&tstructMs.time);
strftime(buf, sizeof(buf), "%Y-%m-%d_%H-%M-%S", &tstruct);
std::stringstream ss (std::stringstream::in | std::stringstream::out);
ss << buf << "-" << std::setfill('0') << std::setw(3) << tstructMs.millitm ;
return ss.str() ;
}
class CAtTrace
{
private :
static CAtTrace * _instance ;
std::ofstream mytr_out ;
int argc ;
char ** argv ;
protected :
CAtTrace() ;
void caclTraceFilePath();
public :
pid_t pid ;
std::string hostname ;
std::string exename ;
std::string traceFilePath ;
static CAtTrace * instance() ;
void setExeName( int argc0, char ** argv0 );
std::ofstream& open();
std::ofstream& printBegin();
void close();
};
#ifdef UTILITIES_TRACE
#define MYMSG_INFO
#define MYTRACE_BEGIN CAtTrace::instance()->open() <<"["<<__LINE__<<"] " <<
#define MYTRACE_END ; CAtTrace::instance()->close()
#define mytr( flow ) MYTRACE_BEGIN flow MYTRACE_END
#define mytrln( flow ) MYTRACE_BEGIN flow << std::endl MYTRACE_END
#define mytrBeginln( flow ) MYTRACE_BEGIN "Begin " << flow << "..." \
<< std::endl MYTRACE_END
#define mytrEndln( flow ) MYTRACE_BEGIN "End " << flow \
<< std::endl MYTRACE_END
#define myscrute(var) mytr( #var << "=" << var )
#define myscruteln(var) mytrln( #var << "=" << var )
#else
#define mytr( flow )
#define mytrln( flow )
#define mytrBeginln( flow )
#define mytrEndln( flow )
#define myscrute(var)
#define myscruteln(var)
#endif
CAtTrace * CAtTrace::_instance = 0 ;
CAtTrace * CAtTrace::instance()
{
if (_instance==NULL)
{
_instance= new CAtTrace() ;
};
return _instance ;
};
void CAtTrace::caclTraceFilePath()
{
std::stringstream ss (std::stringstream::in | std::stringstream::out);
ss << tracePath << hostname << "_" << exename << "_" << pid << "_" \
<< __FILE__ << ".log" ;
ss >> traceFilePath ;
};
CAtTrace::CAtTrace()
{
exename = "NoExeNameSet" ;
char name[ 256 ] ;
gethostname( name, 256 ) ;
hostname = name ;
pid = getpid();
caclTraceFilePath() ;
};
std::ofstream& CAtTrace::printBegin()
{
mytr_out.open( traceFilePath.c_str() , std::ios_base::app
| std::ios_base::out );
mytr_out << currentDateTimeMs() << " " << hostname << " " << exename << " "\
<< pid << " " << __FILE__ ;
return mytr_out;
}
void CAtTrace::setExeName( int argc0, char ** argv0 )
{
argc = argc0 ;
argv = argv0 ;
exename = basename( argv[0] ) ;
caclTraceFilePath();
printBegin();
mytr_out<<"["<<__LINE__<<"] " << "CAtTrace::setExeName " ;
for (int argi = 1 ; argi < argc ; argi++ )
{
mytr_out << " arg[" << argi << "]=[ " << argv[argi] << " ]" ;
}
mytr_out << std::endl ;
};
std::ofstream& CAtTrace::open()
{
printBegin();
return mytr_out;
};
void CAtTrace::close()
{
mytr_out << std::flush ;
mytr_out.close() ;
};
// ATTODO trace end
//##############################################################################
int main( int argc, char *argv[] )
{
CAtTrace::instance()->setExeName( argc, argv ) ;
mytrln("La vie est belle 1 !");
usleep( 5000 ) ;
mytrln("La vie est belle 2 !");
usleep( 4000 ) ;
mytrln("La vie est belle 3 !");
usleep( 1000 ) ;
mytrln("La vie est belle 4 !");
printf( "traceFilePath=%s\n" , CAtTrace::instance()->traceFilePath.c_str());
printf( "more %s\n" , CAtTrace::instance()->traceFilePath.c_str() );
}
6.4 #define
define variables
6.5 #error
display an error message
6.6 #if, #ifdef, #ifndef, #else, #elif, #endif
conditional operators
6.7 #include
insert the contents of another file
6.8 #line
set line and file information
6.9 #pragma
implementation specific command
6.10 #undef
used to undefine variables
6.11 Predefined preprocessor variables
miscellaneous preprocessor variables
- __LINE__
- __FILE__
- __DATE__
- __TIME__
- __cplusplus
- __STDC__
6.12 Voir aussi
7 Opérateurs logique
- &&
- et logique
- II
- ou logique
- !
- non logique
8 Conversions
8.1 unicode, char, wchar_t
8.1.1 c2w
std::wstring & c2w( const std::string & a, std::wstring & b )
{
b = L"" ;
for ( unsigned int i = 0; i < a.size(); i++)
{
b += a[i] ;
}
return b ;
} ;
8.1.2 w2c
std::string & w2c( const std::wstring & a, std::string & b )
{
b = "" ;
for ( unsigned int i = 0; i <a.size(); i++)
{
b += (char)a[i] ;
}
return b ;
} ;
8.2 Texte vers scalaires
8.2.1 stringstream
// using stringstream constructors.
#include <iostream>
#include <sstream>
using namespace std;
int main () {
int val;
stringstream ss (stringstream::in | stringstream::out);
ss << "120 42 377 6 5 2000";
for (int n=0; n<6; n++)
{
ss >> val;
cout << val*2 << endl;
}
return 0;
}
9 Exceptions
#include <iostream>
...
try
{
throw 20;
}
catch (int e)
{
std::cout << "An exception occurred. Exception Nr. " << e << std::endl;
}
#include <exception>
...
class myError : public std::exception
{
private :
std::string _msg ;
public :
myError( const char * what0) : exception( ), _msg( what0 )
{
_msg="myError : "+_msg ;
}
~myError( ) throw()
{}
virtual const char * what( ) const throw()
{
return _msg.c_str();
}
} ;
try
{
...
}
catch (int param) { cout << "int exception"; }
catch (char param) { cout << "char exception"; }
catch (...) { cout << "default exception"; }
9.1 Try Finally
template <class PTR >
class TryFinallyPtr
{
public :
TryFinallyPtr( PTR * * ptr ) : _ptr( ptr ) { }
~TryFinallyPtr( )
{
if ( _ptr != NULL)
{
delete *_ptr ;
*_ptr = NULL ;
_ptr = NULL ;
}
}
private :
PTR * * _ptr ;
} ;
Exemple d'utilisation :
ParadXMLDriver_ns::CFileFormatInfo info ;
ParadXMLDriver_ns::CParadPlatform * med ;
med = info.LoadFromXMLFile( fname ) ;
TryFinallyPtr< ParadXMLDriver_ns::CParadPlatform > TryFinallyMed( &med ) ;
...
10 Lire un caractère depuis la console
10.1 _getch et _getche
10.1.1 Windows
Qu'une touche du clavier soit appuyée ou non _getch renvoie le code de la touche appuyée, n'attend pas l'appui sur une touche.
#include <conio.h>
...
int a = _getch() ;
10.1.2 Linux
Sous Linux, nous n'avons pas la commande équivalente, il faut un plus de code pour avoir l'équivalente.
10.1.2.1 Solution 1
#include <termios.h>
#include <unistd.h>
int mygetch(void)
{
struct termios oldt,
newt;
int ch;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}
10.1.2.2 Solution 2
/**
Linux (POSIX) implementation of _kbhit().
Morgan McGuire, morgan@cs.brown.edu
*/
#include <stdio.h>
#include <sys/select.h>
#include <termios.h>
#include <stropts.h>
int _kbhit() {
static const int STDIN = 0;
static bool initialized = false;
if (! initialized) {
// Use termios to turn off line buffering
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
//////////////////////////////////////////////
// Simple demo of _kbhit()
#include <unistd.h>
int main(int argc, char** argv) {
printf("Press any key");
while (! _kbhit()) {
printf(".");
fflush(stdout);
usleep(1000);
}
printf("\nDone.\n");
return 0;
}
10.2 getchar
getchar lit le code d'une touche de clavier appuyé, il attend, pour rendre la main, l'appui de la touche retour-chariot.
int a = _getch() ;
10.3 std::cin
std::cin permet aussi de lire un caractère au clavier, il attend, pour rendre la main, l'appui d'une touche autre que espace suivi l'appui de la touche retour-chariot.
#include <iostream>
...
char a ;
std::cin >> a ;
10.4 pause, wait_a_char
Voici la commande sui attend l'appui d'une touche au clavier sans demander l'appui sur return pour rendre la main (sous windows et linux).
#ifdef LINUX
#include <termios.h>
#include <unistd.h>
int wait_a_char(void)
{
wprintf( L"Press a key:\n" ) ;
struct termios oldt,
newt;
int ch;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}
#endif
#ifdef WINDOWS
//#include <conio.h>
int wait_a_char()
{
wprintf( L"Press a key:\n" ) ;
int a = _getch() ;
return a
};
#endif
11 Pointeurs
11.1 Pointeurs de fonction
typedef void (*state_func)( wchar_t ) ;
...
void getA( wchar_t a )
{
} ;
state_func a = getA ;
11.2 Pointeurs de méthodes de classe
typedef void (CParsor::*state_func)( wchar_t ) ;
class CParsor
{
protected :
state_func process ;
public:
CParsor() : process(NULL)
{
process = &CParsor::zone_val ;
(this->* process)( L'A' ) ;
};
void zone_val( wchar_t carac )
{
};
};
12 Template
12.1 Template de fonction - concept
template<typename Type>
Type minimum( Type a, Type b)
{
return a < b ? a : b ;
}
template<typename T>
T minimum(T a, T b)
{
return a < b ? a:b;
}
int f(int a, int b)
{
return minimum(a,b) ;
}
float f(float a, float b)
{
return minimum(a,b) ;
}
problème :
template<typename T1, typename T2>
T1 minimum(T1 a, T2 b)
{
return a < b ? a:b;
}
auto x = minimum(3,9.2);
int f(int a, int b)
{
return minimum(a,b) ;
}
float f(float a, float b)
{
return minimum(a,b) ;
}
#include <iostream>
int main(){
std::cout << minimum(3.5,10) << "\n" ;
std::cout << minimum(10,3.5) << "\n" ;
}
donne ! :
3.5
3
Solution un peu olé olé :
template<typename T1, typename T2>
auto minimum(T1 a, T2 b) -> decltype( a<b ? a:b)
{
return a < b ? a:b;
}
auto x = minimum(3,9.2);
int f(int a, int b)
{
return minimum(a,b) ;
}
float f(float a, float b)
{
return minimum(a,b) ;
}
#include <iostream>
int main(){
std::cout << minimum(3.5,10) << "\n" ;
std::cout << minimum(10,3.5) << "\n" ;
}
3.5
3.5
Solution c++ 14 :
template<typename T1, typename T2>
auto minimum(T1 a, T2 b) // c++ 14 optionnel -> decltype( a<b ? a:b)
{
return a < b ? a:b;
}
auto x = minimum(3,9.2);
int f(int a, int b)
{
return minimum(a,b) ;
}
float f(float a, float b)
{
return minimum(a,b) ;
}
#include <iostream>
int main(){
std::cout << minimum(3.5,10) << "\n" ;
std::cout << minimum(10,3.5) << "\n" ;
}
3.5
3.5
A méditer :
template<typename T1, typename T2>
auto minimum(T1 a, T2 b) // c++ 14 optionnel -> decltype( a<b ? a:b)
{
return a < b ? a:b;
}
auto x = minimum(3,9.2);
int f(int a, int b)
{
return minimum(a,b) ;
}
float f(float a, float b)
{
return minimum(a,b) ;
}
#include <iostream>
struct gadget {};
gadget minimum(gadget a, gadget b)
{
return {} ;
}
int main(){
gadget a,b ;
gadget c= minimum(a,b) ;
std::cout << minimum(6,3.5) << "\n" ;
}
la notion de concept :
// concept c++20
#include <iostream>
#include <concepts>
template<typename T1, typename T2>
concept comparable = requires(T1 a1, T2 a2)
{ { a1 < a2 }; };
template<typename T1, typename T2>
concept ordered = requires(T1 a1, T2 a2)
{ { a1.less_than(a2) } -> std::convertible_to<bool>; };
template<typename T1, typename T2>
requires comparable<T1,T2>
auto minimum(T1 a, T2 b)
{ return a < b ? a:b; }
template<typename T1, typename T2>
requires ordered<T1,T2>
auto minimum(T1 a , T2 b)
{ return a.less_than(b) ? a : b; }
int f(int a, int b) { return minimum(a,b); }
float f(float a, float b) { return minimum(a,b); }
double f(double a, int b) { return minimum(a,b); }
struct gadget
{
bool less_than(gadget const&) { return true;}
};
int main(){
gadget a,b ;
gadget c = minimum( a, b) ;
std::cout << minimum(6,3.5) << "\n" ;
std::cout << minimum(3.5,6) << "\n" ;
}
Retournant une classe :
template<class CCLASS> void fileToWideChar( std::string filename, CCLASS& callBackClass )
{
...
callBackClass.takeWideChar( ... )
...
}
12.2 fonctions et classes amies dans un patron
class C {};
void f (int);
template <typename T> class A
{
public:
//...
friend class C;
friend void f (int);
};
A <int> xi;
A<std::string> xs;
12.3 patrons de fonctions et de classes amies dans une classe
template <typename U> class A{/*...*/};
template <typename T> class B
{
public:
//...
template <typename U> friend class A;
};
template <class U> class A{/*…*/};
template <class T> class B
{
public:
// only A<int> and A<string> are friends
friend class A <int>;
friend class A <std::string>;
};
13 Appel de commandes système
13.1 Récupérer le resultat dans un string
non testé
#include <string>
#include <iostream>
#include <stdio.h>
std::string exec(char* cmd) {
FILE* pipe = popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[128];
std::string result = "";
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
pclose(pipe);
return result;
}
14 Fichiers
14.1 chars_to_file
void chars_to_file( std::string filename, std::string text )
{
FILE *f ;
f=fopen( filename.c_str(),"wb") ;
//fwrite( text.c_str(), sizeof(char),text.size(), f ) ;
for ( std::string::iterator c = text.begin(); c != text.end(); c++ )
{
putc( *c, f ) ;
};
fclose( f ) ;
} ;
14.2 file_to_chars
std::string & file_to_chars( std::string filename, std::string & text )
{
text = "" ;
FILE *f ;
f=fopen( filename.c_str(),"r") ;
bool encore = true ;
while( (! feof(f)) && (encore) )
{
char c = getc(f) ;
encore = c != EOF ;
if (encore)
{
text += c ;
};
} ;
fclose( f ) ;
return text ;
} ;
14.3 file_exists
#include <fstream> // std::ifstream
bool file_exists (const std::string &filename)
{
std::ifstream infile( filename.c_str() );
return infile.good() ;
}
14.4 fileTxt_to_fileTxt_by_word
Al1 |
Le fait d'utiliser des formats textes ne garantie pas la copie exacte des fichiers |
#include <fstream> // std::ifstream, std::ofstream
#include <string> // std::string
void fileTxt_to_fileTxt_by_word( const char * filetxt1, const char * filetxt2 )
{
std::ifstream ifs ( filetxt1 );
std::ofstream ofs ( filetxt2 );
if (ofs.good ())
{
std::string s;
while (ifs >> s)
{
ofs << s << ' ';
} ;
}
}
14.5 fileTxt_to_fileTxt_by_line
Al2 |
Le fichier destination aura toujours une saut de ligne en fin de fichier. |
#include <fstream> // std::ifstream, std::ofstream
#include <string> // std::string, std::getline()
#include <iostream> // std::endl
int fileTxt_to_fileTxt_by_line( const char * filetxt1, const char * filetxt2 )
{
std::ifstream ifs ( filetxt1 );
std::ofstream ofs ( filetxt2 ) ;
std::string s;
while ( std::getline (ifs, s) )
ofs << s << std::endl ;
}
14.6 Lire un fichier texte ligne par ligne et colonne par colonne
//---------------------------------------------------------------------------
#include <iostream>
#include <fstream.h>
#include <strings.h>
#include <sstream.h>
// voir http://www.msoe.edu/eecs/ce/courseinfo/stl/string.htm
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
std::ifstream fic("entree.txt");
if ( ! fic.is_open( ) ) { std::cout << "Error opening file"; exit (1); }
std::string line ;
while ( getline( fic , line , '\n') )
{
std::cout << line << std::endl ;
std::stringstream sline( line ) ;
std::string mot ;
while ( ! sline.eof() )
{
sline >> mot ;
std::cout << mot << std::endl ;
} ;
}
return 0;
}
//---------------------------------------------------------------------------
Comment manipuler des fichiers
14.7 Liens
15 Héritage
15.1 Héritage non virtuelle
#include <iostream>
class classK
{
public :
int x ;
classK() : x(0)
{
std::cout << "classK::classK()" << std::endl ;
} ;
virtual ~classK()
{
std::cout << "classK::~classK()" << std::endl ;
} ;
virtual void copy( classK * obj )
{
std::cout << "classK::copy( classK * obj )" << std::endl ;
x = obj->x ;
} ;
virtual void clear()
{
std::cout << "classK::clear()" << std::endl ;
x = 0 ;
} ;
};
class classA : public classK
{
public :
classA() : classK()
{
std::cout << "classA::classA()" << std::endl ;
x = 1 ;
} ;
~classA()
{
std::cout << "classA::~classA()" << std::endl ;
} ;
void copy( classK * obj )
{
std::cout << "classA::copy( classK * obj )" << std::endl ;
classK::copy( obj ) ;
} ;
void copy( classA * obj )
{
std::cout << "classA::copy( classA * obj )" << std::endl ;
classK::copy( obj ) ;
} ;
void clear()
{
std::cout << "classA::clear()" << std::endl ;
classK::clear() ;
} ;
};
class classB : public classK
{
public :
classB() : classK()
{
std::cout << "classB::classB()" << std::endl ;
x = 2 ;
} ;
~classB()
{
std::cout << "classB::~classB()" << std::endl ;
} ;
void copy( classK * obj )
{
std::cout << "classB::copy( classK * obj )" << std::endl ;
classK::copy( obj ) ;
} ;
void copy( classB * obj )
{
std::cout << "classB::copy( classB * obj )" << std::endl ;
classK::copy( obj ) ;
} ;
void clear()
{
std::cout << "classB::clear()" << std::endl ;
classK::clear() ;
} ;
};
class classC : public classA, classB
{
/*
La class C contient deux espaces mémoire distinctes pour l'ancetre classK ;
classA::classK et classB::classK
*/
public :
classC() : classA(), classB()
{
std::cout << "classC::classC()" << std::endl ;
} ;
~classC()
{
std::cout << "classC::~classC()" << std::endl ;
} ;
void copy( classK * obj )
{
std::cout << "classC::copy( baseK* obj )" << std::endl ;
classA::copy( obj ) ;
classB::copy( obj ) ;
} ;
void copy( classC * obj )
{
std::cout << "classC::copy( baseC* obj )" << std::endl ;
classA::copy( (classA * )obj ) ;
classB::copy( (classB * )obj ) ;
} ;
void clear()
{
std::cout << "classC::clear()" << std::endl ;
classA::clear() ;
classB::clear() ;
} ;
void print()
{
std::cout << "classA::x = " << classA::x << std::endl ;
std::cout << "classB::x = " << classB::x << std::endl ;
} ;
};
int main(int argc, char *argv[ ])
{
classC * c = new classC() ;
classC c2 ;
classA * a = (classA *) c ;
classB * b = (classB *) c ;
classK * ka = (classK *)(classA *) c ;
classK * kb = (classK *)(classB *) c ;
//classK * kk = (classK *) c ; error: 'classK' is an ambiguous base of 'classC'
//classK * k = (classC *) c ; error: 'classK' is an ambiguous base of 'classC'
classK * ka2 = (classK* )(classA *) &c2 ;
c->print() ;
c2.print() ;
ka->clear() ;
c->print() ;
ka->copy( ka2 ) ;
c->print() ;
// pb car on appelle que le classK de classA => ka2,
//le polymorphisme de copy ne suffit pas pour une utilisation claire.
c->copy( &c2 ) ;
c->print() ;
// ici on maîtrise mieux la copie, mais on a perdu le polymorphisme.
delete c ;
return 0 ;
} ;
[atoross@claui2v9 /local01/atoross/dvlp/bin/attools/trunk/cpp]$./bin/heritage
classK::classK()
classA::classA()
classK::classK()
classB::classB()
classC::classC()
classK::classK()
classA::classA()
classK::classK()
classB::classB()
classC::classC()
classA::x = 1
classB::x = 2
classA::x = 1
classB::x = 2
classC::clear()
classA::clear()
classK::clear()
classB::clear()
classK::clear()
classA::x = 0
classB::x = 0
classC::copy( baseK* obj )
classA::copy( classK * obj )
classK::copy( classK * obj )
classB::copy( classK * obj )
classK::copy( classK * obj )
classA::x = 1
classB::x = 1
classC::copy( baseC* obj )
classA::copy( classA * obj )
classK::copy( classK * obj )
classB::copy( classB * obj )
classK::copy( classK * obj )
classA::x = 1
classB::x = 2
classC::~classC()
classB::~classB()
classK::~classK()
classA::~classA()
classK::~classK()
classC::~classC()
classB::~classB()
classK::~classK()
classA::~classA()
classK::~classK()
15.2 Héritage virtuel
#include <iostream>
class classK
{
public :
int x ;
classK() : x(0)
{
std::cout << "classK::classK()" << std::endl ;
} ;
virtual ~classK()
{
std::cout << "classK::~classK()" << std::endl ;
} ;
virtual void copy( classK * obj )
{
std::cout << "classK::copy( classK * obj )" << std::endl ;
x = obj->x ;
} ;
virtual void clear()
{
std::cout << "classK::clear()" << std::endl ;
x = 0 ;
} ;
};
class classA : public virtual classK
{
public :
classA() : classK()
{
std::cout << "classA::classA()" << std::endl ;
} ;
~classA()
{
std::cout << "classA::~classA()" << std::endl ;
} ;
void copy( classK * obj )
{
std::cout << "classA::copy( classK * obj )" << std::endl ;
classK::copy( obj ) ;
} ;
void copy( classA * obj )
{
std::cout << "classA::copy( classA * obj )" << std::endl ;
classK::copy( obj ) ;
} ;
void clear()
{
std::cout << "classA::clear()" << std::endl ;
classK::clear() ;
} ;
};
class classB : public virtual classK
{
public :
classB() : classK()
{
std::cout << "classB::classB()" << std::endl ;
} ;
~classB()
{
std::cout << "classB::~classB()" << std::endl ;
} ;
void copy( classK * obj )
{
std::cout << "classB::copy( classK * obj )" << std::endl ;
classK::copy( obj ) ;
} ;
void copy( classB * obj )
{
std::cout << "classB::copy( classB * obj )" << std::endl ;
classK::copy( obj ) ;
} ;
void clear()
{
std::cout << "classB::clear()" << std::endl ;
classK::clear() ;
} ;
};
class classC : public classA, classB
{
/*
La class C contient deux espaces mémoire distinctes pour l'ancetre classK ;
classA::classK et classB::classK
*/
public :
classC() : classA(), classB()
{
std::cout << "classC::classC()" << std::endl ;
} ;
~classC()
{
std::cout << "classC::~classC()" << std::endl ;
} ;
void copy( classK * obj )
{
std::cout << "classC::copy( baseK* obj )" << std::endl ;
classA::copy( obj ) ;
classB::copy( obj ) ;
} ;
void copy( classC * obj )
{
std::cout << "classC::copy( baseC* obj )" << std::endl ;
classA::copy( (classA * )obj ) ;
classB::copy( (classB * )obj ) ;
} ;
void clear()
{
std::cout << "classC::clear()" << std::endl ;
classA::clear() ;
classB::clear() ;
} ;
void print()
{
std::cout << "x = " << x << std::endl ;
} ;
};
int main(int argc, char *argv[ ])
{
classC * c = new classC() ;
classC c2 ;
classK * k = (classK *)c ;
c->print() ;
c2.print() ;
k->clear() ;
c->print() ;
// pb double clear de classK
c2.x =3 ;
k->copy( (classK*) &c2 ) ;
c->print() ;
// pb double copy de classK
c2.x =4 ;
c->copy( &c2 ) ;
c->print() ;
// pb double copy de classK
delete c ;
return 0 ;
} ;
[atoross@claui2v9 /local01/atoross/dvlp/bin/attools/trunk/cpp]$./bin/heritage2
classK::classK()
classA::classA()
classB::classB()
classC::classC()
classK::classK()
classA::classA()
classB::classB()
classC::classC()
x = 0
x = 0
classC::clear()
classA::clear()
classK::clear()
classB::clear()
classK::clear()
x = 0
classC::copy( baseK* obj )
classA::copy( classK * obj )
classK::copy( classK * obj )
classB::copy( classK * obj )
classK::copy( classK * obj )
x = 3
classC::copy( baseC* obj )
classA::copy( classA * obj )
classK::copy( classK * obj )
classB::copy( classB * obj )
classK::copy( classK * obj )
x = 4
classC::~classC()
classB::~classB()
classA::~classA()
classK::~classK()
classC::~classC()
classB::~classB()
classA::~classA()
classK::~classK()
15.3 Utilisation de méthodes virtuelles, pure ou impure, dans les constructeurs et destructeurs de classes
Si l'on veut avoir un moyen d'intercepter la destruction d'une classe sans avoir à écrire le destructeur de la classe dérivée on peut faire appel à une méthode virtuelle pure, ici appelée onEnd.
Mais, hélas le code suivant ne se compile pas :
class A
{
public :
A()
{
printf("A\n");
} ;
virtual ~A()
{
printf("~A\n");
onEnd() ;
} ;
virtual void onEnd() = 0 ;
};
class B : public A
{
public :
B()
{
printf("B\n");
} ;
~B()
{
printf("~B\n");
} ;
void onEnd()
{
printf("B::onEnd\n");
};
};
int main( int argc, char** argv )
{
printf("Start\n");
B b ;
printf("End\n");
} ;
Le compilateur râle :
undefined reference to `A::onEnd()'
En cherchant sur le net je suis tombé sur :
- Citation : Norme C++ (10.4)
- Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined.
Le problème soulevé ici ce n'est pas le fait que le compilateur refuse de compiler, mais c'est que le compilateur accepte de compiler le code suivant :
#include <algorithm>
#include <vector>
#include <sstream>
class A
{
public :
A()
{
printf("A\n");
} ;
virtual ~A()
{
printf("~A\n");
onEnd() ;
} ;
virtual void onEnd()
{
printf("A::onEnd\n");
} ;
};
class B : public A
{
public :
B()
{
printf("B\n");
} ;
~B()
{
printf("~B\n");
} ;
void onEnd()
{
printf("B::onEnd\n");
};
};
int main( int argc, char** argv )
{
printf("Start\n");
B b ;
printf("End\n");
} ;
En exécutant le programme on obtient :
Start
A
B
End
~B
~A
A::onEnd
Al3 |
Nous voyons bien que la méthode virtuelle onEnd ne se comporte pas comme une méthode virtuelle dans le destructeur ! Si on ne fait pas attention, cela peut conduire à des bugs dans le programme. |
Je ne comprends pas pourquoi ceci, car le compilateur peut détruire la table des méthodes virtuelles à la fin du destructeur. Dans d'autre langages tel que le pascal j'utilise des méthodes virtuelles dans les destructeurs.
Vérifier en pascal ce qui est dit ci-dessus.
Que faire alors ? Pour l'instant je n'ai trouvé que le moyen de ré-écrire le destructeur de la classe dérivée, on perd alors la sémantique donnée par le nom de la méthode onEnd ; ce qui signifie évènement arrivé avant la destructeur de la classe, ou alors il faut demander à l'utilisateur de l'API de rappeler onEnd dans le destructeur de sa classe.
Voici le code
#include <algorithm>
#include <vector>
#include <sstream>
class A
{
public :
A()
{
printf("A\n");
} ;
virtual ~A()
{
printf("~A\n");
onEnd() ;
} ;
virtual void onEnd()
{
printf("A::onEnd\n");
} ;
};
class B : public A
{
public :
B()
{
printf("B\n");
} ;
~B()
{
printf("~B\n");
onEnd() ;
} ;
void onEnd()
{
printf("B::onEnd\n");
};
};
int main( int argc, char** argv )
{
printf("Start\n");
B b ;
printf("End\n");
} ;
Programme exécuté donne :
Start
A
B
End
~B
B::onEnd
~A
A::onEnd
16 Singleton
Interface :
class CTestBase_factory
{
private :
static CTestBase_factory * _instance ;
protected :
map_factory_t creators ;
CTestBase_factory() ;
public :
static CTestBase_factory * instance() ;
CTestBase * create( const char * classname ) ;
void register_creator( const char * classname, create_func_t create_func ) ;
};
Implémentation :
CTestBase_factory * CTestBase_factory::_instance = 0 ;
CTestBase_factory * CTestBase_factory::instance()
{
if (_instance==NULL)
{
_instance= new CTestBase_factory() ;
};
return _instance ;
};
CTestBase_factory::CTestBase_factory() : creators()
{
register_creator( "CTest", CTest_factory ) ;
...
};
CTestBase * CTestBase_factory::create( const char * classname )
{
return creators[ classname ]() ;
};
void CTestBase_factory::register_creator( const char * classname, create_func_t create_func )
{
creators[ classname ] = create_func ;
};
17 Surchage d'opérateurs
17.1 opérateur []
#include <iostream>
class classA
{
protected :
float rayon ;
float nan ;
public :
classA() : nan(0.0), rayon( 1.2 ) {} ;
~classA() {} ;
};
class classB : public classA
{
public :
classB() : classA() {} ;
~classB() {} ;
float & operator []( int index )
{
if (index==1) { return rayon ; }
else { return nan ; }
}
};
int main(int argc, char *argv[ ])
{
classB b ;
for (int i = 0; i< 10 ; i++) { std::cout << b[ i ] << std::endl ; }
b[ 1 ] = 5.6 ;
b[ 5 ] = 8.5 ;
for (int i = 0; i< 10 ; i++) { std::cout << b[ i ] << std::endl ; }
return 0 ;
} ;
Rq | La valeur de retour comme référence float & permet de l'assignement b[ 1 ] = 5.6 |
Ce qui donne :
0
1.2
0
0
0
0
0
0
0
0
8.5
5.6
8.5
8.5
8.5
8.5
8.5
8.5
8.5
8.5
18 typecasting
18.1 RTTI : typeid
Exemple simple :
#include <typeinfo>
...
int X ;
std::cout << "type de X " << typeid( X ).name() << std::endl ;
...
int *X ;
std::cout << "type de X " << typeid( X ).name() << std::endl ;
std::cout << "type de X " << typeid( *X ).name() << std::endl ;
...
Exemple plus complet :
// typeid, polymorphic class
#include <iostream>
#include <typeinfo>
#include <exception>
using namespace std;
class CBase { virtual void f(){} };
class CDerived : public CBase {};
int main () {
try {
CBase* a = new CBase;
CBase* b = new CDerived;
cout << "a is: " << typeid(a).name() << '\n';
cout << "b is: " << typeid(b).name() << '\n';
cout << "*a is: " << typeid(*a).name() << '\n';
cout << "*b is: " << typeid(*b).name() << '\n';
} catch (exception& e) { cout << "Exception: " << e.what() << endl; }
return 0;
}
donne :
a is: class CBase *
b is: class CBase *
*a is: class CBase
*b is: class CDerived
18.2 Voir aussi
19 STL
19.1 vector, les vecteurs ou tableaux
19.1.1 Parcourir les vecteurs
#include <iostream>
#include <vector>
using namespace std ;
int main()
{
vector< size_t > V(5) ;
V[4] = 4 ;
V[3] = 3 ;
V[2] = 2 ;
V[1] = 1 ;
V[0] = 0 ;
vector< size_t >::iterator v = V.end() ;
v-- ;
while (v >= V.begin() )
{
cout << *v << endl ;
v-- ;
};
cout << "--" << endl ;
v = V.begin();
while (v < V.end() )
{
cout << *v << endl ;
v++ ;
};
return 0 ;
}
19.2 map, les dictionnaires
std::map<const char*, int > a ;
a["toto"] = 1 ;
a["titi"] = 2 ;
std::cout << a["toto"] << std::endl ;
std::cout << a["toti"] << std::endl ;
donne
1
0
Rq | Si la clé n'est pas trouvé, la valeur par défaut du type est renvoyée. |
20 Avec des sources UTF8
20.1 avec utf8-cpp
#include <iostream>
#include <string>
#include <clocale>
#include <utf8.h>
int main() {
char* local = setlocale(LC_CTYPE,"");
std::cout << "local : " << local << std::endl ;
std::string txt = "Cet été je serai en vacances. Le nombre π vaut 3.14. Voici une phrase écrite en arménien; «Կյանքը գեղեցիկ Ե»" ;
std::cout << "txt : " << txt << std::endl ;
std::wstring wtxt ;
utf8::utf8to16( txt.begin(), txt.end(), back_inserter(wtxt) ) ;
std::string txtc ;
utf8::utf16to8( wtxt.begin(), wtxt.end(), back_inserter(txtc) ) ;
std::cout << "txtc : " << txtc << std::endl ;
return 0;
};
ce qui produit :
local : fr_FR.UTF-8
txt : Cet été je serai en vacances. Le nombre π vaut 3.14. Voici une phrase écrite en arménien; «Կյանքը գեղեցիկ Ե»
txtc : Cet été je serai en vacances. Le nombre π vaut 3.14. Voici une phrase écrite en arménien; «Կյանքը գեղեցիկ Ե»
20.2 Avec c++11
- source : [4]
- Voir aussi string literal (L, u8, u, U, R)
20.3 Conversion d'un « string »
#include <cstdlib>
#include <iostream>
#include <locale.h>
#include <string>
#include <locale>
#include <codecvt>
#include <cassert>
int main() {
const auto str = u8"Cet été je serai en vacances. Le nombre π vaut 3.14. Voici une phrase écrite en arménien; «Կյանքը գեղեցիկ Ե»";
wstring_convert<codecvt_utf8<char32_t>, char32_t> cv;
auto str32 = cv.from_bytes(str);
for (auto c : str32)
cout << uint_least32_t(c) << '\n';
return 0;
}
20.4 Conversion d'un « fichier »
#include<iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstdint>
#include <locale>
#include <codecvt>
using namespace std;
std::wstring convert(const std::string& input)
{
try
{
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
return converter.from_bytes(input);
}
catch (std::range_error& e)
{
size_t length = input.length();
std::wstring result;
result.reserve(length);
for (size_t i = 0; i < length; i++)
{
result.push_back(input[i] & 0xFF);
}
return result;
}
}
int main()
{
// read entire file into string
if (std::ifstream is{ "C:\\Users\\hsingh\\Documents\\Visual Studio 2017\\Projects\\ConsoleApplication4\\Debug\\test.txt", std::ios::binary
21 Expressions régulières
#include <iostream>
#include <string>
#include <regex>
int main()
{
// Regular Expression TR1 Example
// Create a string - This is what we will search
const std::string SearchString("Hello World, My email is tom@lolfake.com");
// Let's grab the email address
const std::tr1::regex RegPtnEmail("([\\w-+]+(?:\\.[\\w-+]+)*@(?:[\\w-]+\\.)+[a-zA-Z]{2,7})");
std::tr1::smatch Result;
if (std::tr1::regex_search(SearchString, Result, RegPtnEmail))
std::cout << Result[1] << std::endl;
else
std::cerr << "No Email found" << std::endl;
// Let's try a different email
const std::string NewEmail("asdasdasdasdasd lol@gmail.com");
if (std::tr1::regex_search(NewEmail, Result, RegPtnEmail))
std::cout << Result[1] << std::endl;
else
std::cerr << "No Email found" << std::endl;
// Let's try a unfinished email
const std::string FakeEmail("Hello - - lol@gmail");
if (std::tr1::regex_search(FakeEmail, Result, RegPtnEmail))
std::cout << Result[1] << std::endl;
else
std::cerr << "No Email found" << std::endl;
return 0;
}