C++

Astuces Visual Studio

Probleme du const int global pour declarer un tableau: http://bytes.com/topic/c/answers/222781-specifying-global-array-size-const-int

It does distinguish between a literal and a const int in either
context. The difference is that variable length arrays (VLAs) are
legal in a local context. In the following:

int main(void)
{
#define TEN 10
const int ten = 10;
int arr0[TEN];
int arr1[ten];
...
}

arr0 is an ordinary array, but arr1 is a VLA.

Excellent cours (avec lib standard):
http://casteyde.christian.free.fr/cpp/cours/online/c207.html

http://www.cplusplus.com/doc/tutorial/

Bonne Faq:
http://cpp.developpez.com/faq/cpp/

analyse statique - static analysis

If by Open Source, you really meant "free", then Microsoft's prefast analysis is a good one. Windows-only ofcourse. It is fully integrated in Visual Studio & the compiler. e.g.:
cl /analyze Sample.cpp

Concerning the GNU compiler, gcc has already a builtin option that enables additional warning to those of -Wall. The option is -Weffc++ and it's about the violations of some guidelines of Scott Meyers published in his books "Effective and More Effective C++".

CppCheck is open source and cross-platform.
https://wiki.mozilla.org/Static_Analysis
http://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis#C.2FC.2B.2B

diagram uml reverse engineering C++

C++ tips

If you use [] when you call new, you must use [] when you call delete. If you don ' t use [] when you call new, don ' t use [] when you call delete.

Prefer C++-style comments

Prefer new and delete to malloc and free. The problem with malloc and free (and their variants) is simple:

they don't  know about  constructors an destructors.

Prefer <iostream > to <stdio.h>

"prefer the compiler to the preprocessor

const double ASPECT_RATIO = 1.653; class GamePlayer {

private:
	static const int NUM_TURNS = 5;    // constant declaration
	int scores[NUM_TURNS];             // use of constant
	...

};

const int GamePlayer::NUM_TURNS; m Use delete on pointer members in dest ructors. Until 1993, C++ required that operator new return 0 when it was unable to satisfy a memory request. The current behavior is for operator new to throw a std::bad_allocexception The easiest way to do that is to take advantage of set_new_handler, because it works with both forms La norme ISO C99 impose de définir des types portables afin de régler ces problèmes sur toutes les architectures existantes. Ces types sont définis dans le fichier d'en-tête stdint.h. Il s'agit des types int8_t, int16_t, int32_t et int64_t, et de leurs versions non signées uint8_t, uint16_t, uint32_t et uint64_t. Instance/classes constructeur/destructeur(virtual)/constructeur de copie <code> class MaClasse { public: MaClasse( const MaClasse & ); ceci est le constructeur de copie }; </code>

pointeurs/references/passage par valeur
lifting = rafinement de templates
partie publique = interface
encapsulation=
J'applique une méthode simple : la question à se poser est la suivante : est-ce que X est un genre de Y, ou est-ce que X utilise un Y ?
Si la réponse est X est un genre de Y, il s'agit d'un cas où je dérive une classe.
Si la réponse est X utilise Y, il s'agit d'un cas où je vais encapsuler une classe.

Le polymorphisme, c'est la capacité d'une expression à être valide quand les valeurs présentes ont des types différents. On trouve différents types de polymorphismes :

class Person
{
public:
    // accesseur : renvoie le nom
    const std::string & GetName() const // notez le const
    {
        return this->name;
    }
 
    // mutateur : change le nom
    void SetName( const std::string & NewName )
    {
        this->name = NewName;
    }
 
private:
    std::string name; // nom de la personne
};

Qu'est-ce que la coercition ?
Derrière cette expression se cache tout simplement les mécanismes de conversion implicite

double result = op1 + op2; // polymorphisme de coercition


Qu'est-ce que la surcharge ?
Il s'agit probablement d'une des premières caractéristiques du C++ présentées : la capacité à surcharger une opération avec différentes signatures

Qu'est-ce que le polymorphisme paramétrique ?
Le polymorphisme paramétrique passe par l'utilisation des techniques génériques pour offrir un même service pour tout un ensemble de types

template<class T>
void dump(T var)
{
   std::cout<<Timestamp()<<" : "<<var<<std::endl;
}

Qu'est-ce que le polymorphisme d'inclusion ?
Souvent résumé tout simplement (et trop hativement) à 'polymorphisme', le polymorphisme d'inclusion s'appuie sur l'héritage public
fonctions virtuelles

void function(IInterface const &var_)
{
   var_.Action();
}
class IInterface
{//...
};
class CConcrete : public IInterface
{//...
};
 
int main()
{
   CConcrete c;
   Fonction(c);
   return 0;
}
class Widget
{
  public:
  virtual ~Widget() { /* ... */ }
  void show()
  {
    // ...
    do_show();
    // ...
  }
  // ...
 
  private : 
    virtual void do_show()=0; // fonction virtuelle pure
};
 
class Button : public Widget
{
  private : 
    virtual void do_show() { std::cout << "Button" << std::endl; }
  // ...
};
 
class Textfield : public Widget
{
  private : 
    virtual void do_show() { std::cout << "Textfield" << std::endl; }
  // ...
};
 
void show_widget(Widget& w)
{
  w.show();
}
 
/* ... */
 
Button b;
Textfield t;
 
show_widget(b); // affiche "Button"
show_widget(t); // affiche "Textfield"
 

Quels sont les enjeux associés aux techniques Orientées Objets ?
Les techniques OO sont la meilleure façon connue de développer de grosses applications ou des systèmes complexes.

L'industrie du logiciel n'arrive pas à satisfaire les demandes pour des systèmes logiciels aussi imposants que complexes, mais cet échec est dû à nos succès : nos réussites ont habitué les utilisateurs à toujours en demander plus. Malheureusement, nous avons ainsi créé une demande du marché que les techniques 'classiques' de programmation ne pouvaient satisfaire. Cela nous a obligé à créer un meilleur paradigme.

le C++ permet de programmer OO, mais il peut aussi être utilisé comme un langage classique ("un C amélioré"). Si vous comptez l'utiliser de cette façon, n'espérez pas profiter des bénéfices apportés par la programmation OO.

Fred* p = new Fred();
Le destructeur Fred::~Fred() va être appelé automatiquement quand vous utiliserez delete
 Sélectionnez

 Que signifie 'friend' ?
Quelque chose qui permet à une classe d'offrir des droits d'accès privilégiés à une autre classe ou fonction.

const signale que la variable ne peut pas changer de valeur, et que le compilateur refusera qu'on le fasse.

static (dans le cas de la classe) signifie que la variable n'existe qu'en un seul exemplaire, elle est globale à la classe en quelque sorte. Autrement, chaque objet du type de la classe dispose de sa propre copie.

Une telle syntaxe (déclaration et définition en un seul coup) est possible en C++, mais seulement parce qu'elle vérifie certaines conditions : il s'agit d'une variable constante, statique, et de type entier. En d'autres termes ces déclarations ne compileraient pas :

 Sélectionnez
class MaClasse
{
    static int x = 0; // erreur : pas constant
    const int y = 5; // erreur : pas statique
    static const float z = 4.2f; // erreur : pas entier
};
delete p; // p->~Fred() est appelé automatiquement



Qu'est-ce que le "fiasco dans l'ordre d'initialisation des variables statiques" ?
Un moyen subtil de planter votre programme.

Le fiasco dans l'ordre d'initialisation des variables statiques est un des aspects les plus subtils et habituellement mal compris du C++. Malheureusement, il est très difficile à détecter étant donné que l'erreur se produit avant même le début de l'exécution du main().

Supposons que l'on ait deux objets statiques x et y qui se trouvent dans des fichiers sources séparés (x.cpp et y.cpp) Supposons ensuite que l'initialisation de l'objet y (typiquement le constructeur de l'objet y) appelle une fonction membre de l'objet x.

C'est aussi simple que cela.

La tragédie est que vous avez 50% de chances de vous planter. S'il arrive que l'unité de compilation correspondant à x.cpp soit initialisée avant celle correspondant à y.cpp, tout va bien. Mais si l'unité de compilation correspondant à y.cpp est initialisée d'abord, alors le constructeur de y sera en route avant le constructeur de x, et vous êtes cuit. C'est-à-dire que le constructeur de y appellera une fonction de l'objet x, alors que ce dernier n'est pas encore construit.

Si vous pensez que c'est "excitant" de jouer à la roulette russe avec la moitié du barillet chargé, vous pouvez vous arrêter de lire ici. Si au contraire vous aimez augmenter vos chances de survie en prévenant les désastres de manière systématique, vous serez probablement intéressé par la question suivante.

Note : le fiasco dans l'ordre d'initialisation des variables statiques peut aussi se produire, dans certains cas, avec les types de base.


#include "Fred.hpp"
 
Fred& x()
{
    static Fred* ans = new Fred();
    return *ans;
}


Que signifient public, private et protected ?
Un membre déclaré public dans une classe peut être accédé par toutes les autres classes et fonctions.
Un membre déclaré protected dans une classe ne peut être accédé que par les autres membres de cette même classe ainsi que par les membres des classes dérivées.
Un membre déclaré private dans une classe ne peut être accédé que par les autres membres de cette même classe.

Ces mots-clés permettent également de modifier la visibilité des membres dans la classe dérivée lors d'un héritage :

                               Héritage
Accès aux données	public	protected	private
public	                public	protected	private
protected	        protected	protected	private
private	                interdit	interdit	interdit

Quand dois-je faire un héritage public ? protégé ? privé ?
public : uniquement si l'héritage porte une sémantique EST-UN ;
privé : lorsque l'héritage porte une sémantique EST-IMPLEMENTE-EN-TERMES-DE et ne supporte pas la sémantique EST-UN ;
protégé : si vous avez une bonne raison, la rédaction sera curieuse de la connaître.


Le LSP (pour Liskov substitution principle) est un principe général de programmation s'énonçant de la façon suivante :

 Sélectionnez

Partout où un objet x de type T est attendu, on doit pouvoir passer un objet y type U, avec U héritant de T.


 Pouvez-vous me donner une raison simple pour laquelle la virtualité est si importante ?
L'appel dynamique permet d'augmenter la réutilisabilité en autorisant le 'vieux' code à appeler du nouveau code.

Avant l'apparition de l'orientation objet, la réutilisation du code se faisait en appelant du vieux code à partir du nouveau code. Par exemple, un programmeur peut écrire du code appelant du code réutilisable comme printf(), ....

Avec l'orientation objet, la réutilisation peut aussi être accomplie via l'appel de nouveau code par de l'ancien. Par exemple, un programmeur peut écrire du code qui est appelé par un framework qui a été écrit par son arrière grand-père. Il n'y a pas besoin de modifier le code écrit par l'arrière grand-père. En fait, il n'a même pas besoin d'être recompilé. Et si jamais il ne restait que le fichier objet, et que le code écrit par l'arrière grand-père ait été perdu depuis 25 ans, cet ancien fichier objet appellera le code avec les nouvelles fonctionnalités sans rien changer d'autre.

C'est cela l'extensibilité, et c'est cela l'orientation objet.


 Les fonctions virtuelles sont-elles un mécanisme important en C++ ?
OUI

Sans les fonctions virtuelles, le C++ ne serait pas un langage orienté objet.


Une fonction virtuelle signifie qu'elle peut être supplantée par une fonction d'une classe fille.
Une fonction virtuelle pure signifie qu'elle doit être supplantée par une fonction d'une classe fille.

STL - Standard Template Library

STL en UML

http://www.cplusplus.com/reference/stl/

http://www.commentcamarche.net/faq/11255-introduction-a-la-stl-en-c-standard-template-library

http://www.sgi.com/tech/stl/table_of_contents.html

#include <list> 
#include <iostream> 

int main() { 
  std::list<int> ma_liste; 
  ma_liste.push_back(4); 
  ma_liste.push_back(5); 
  ma_liste.push_back(4); 
  ma_liste.push_back(1); 
  std::list<int>::const_iterator 
    lit (ma_liste.begin()), 
    lend(ma_liste.end()); 
  for(;lit!=lend;++lit) std::cout << *lit << ' '; 
  std::cout << std::endl;  
  return 0; 
} 
#include <vector> 
#include <iostream> 

int main() { 
  std::vector<int> mon_vecteur; 
  mon_vecteur.push_back(4); 
  mon_vecteur.push_back(2); 
  mon_vecteur.push_back(5); 

  // Pour parcourir un vector (même const) on peut utiliser les iterators ou les index 
  for(std::size_t i=0;i<mon_vecteur.size();++i) {
    std::cout << mon_vecteur[i] << ' ';
  }
  std::cout << std::endl; 

  std::vector<int> mon_vecteur(5,69); // crée le vecteur 69,69,69,69,69 
  v[0] = 5; 
  v[1] = 3; 
  v[2] = 7; 
  v[3] = 4; 
  v[4] = 8; 
  return 0; 
} 
#include <map> 
#include <string> 
#include <iostream> 

int main() { 
  std::map<std::string,unsigned> map_mois_idx; 
  map_mois_idx["janvier"] = 1; 
  map_mois_idx["février"] = 2; 
  //... 
  std::map<std::string,unsigned>::const_iterator 
    mit (map_mois_idx.begin()), 
    mend(map_mois_idx.end()); 
  for(;mit!=mend;++mit) {
    std::cout << mit->first << '\t' << mit->second << std::endl; 
  }
  return 0; 
}

Principaux Design Patterns

M:/SanDiegoWWW/www/dokuwiki/data/pages/san.cplusplus/start.txt · Dernière modification: 2017/02/01 15:26 par admin
 
Sauf mention contraire, le contenu de ce wiki est placé sous la licence suivante : CC Attribution-Noncommercial 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki