60 votes

C ++ pour un développeur C #

Je suis une .NET développeur, et a travaillé avec VB6 avant que. Je suis devenu très familier avec les environnements de travail et dans le contexte de déchets ramassés langues. Cependant, je souhaite renforcer mes compétences avec C++ natif et me trouve un peu dépassé. Ironiquement, ce n'est pas ce que j'imagine, c'est l'habituel pierres d'achoppement pour les débutants car j'ai l'impression que j'ai eu à la portée de pointeurs et gestion de la mémoire assez bien. La chose qui est un peu déroutant pour moi, c'est plus le long des lignes de:

  • Référencement/en utilisant d'autres bibliothèques
  • Exposer mes bibliothèques à utiliser pour les autres
  • La manipulation des chaînes
  • Conversions de types de données
  • Bonne structure de projet
  • Structures de données à utiliser (c'est à dire. en C#, j'utilise List<T> beaucoup, que dois-je utiliser en C++ qui fonctionne simiarly?)

Il se sent presque comme selon l'IDE que vous utilisez, les lignes directrices sont différents, donc j'étais vraiment à la recherche de quelque chose qui est peut-être un peu plus universel. Ou, au pire, axé sur l'utilisation de Microsoft compilateur/IDE. Aussi, juste pour être clair, je ne suis pas à la recherche de quelque chose à propos de la programmation en général des pratiques (Modèles de Conception, Code, etc.) comme je sens que je suis assez bien versé dans ces sujets.

201voto

jalf Points 142628

Je sais que vous dites que vous avez une bonne connaissance des pointeurs et gestion de la mémoire, mais je voudrais encore expliquer ce qu'est une chose importante. Comme une règle générale, ne jamais avoir de new/delete de votre code d'utilisateur.

Chaque acquisition des ressources (qu'il s'agisse d'un verrou de synchronisation, une connexion de base de données ou d'une partie de la mémoire ou quoi que ce soit d'autre qui doit être acquis et publié) doivent être encapsulées dans un objet afin que le constructeur effectue l'acquisition, et le destructeur de communiqués de la ressource. La technique est connue comme le RAII, et c'est en fait la façon d'éviter les fuites de mémoire. Habituez à elle. Le C++ standard library évidemment l'utilise largement, de sorte que vous pouvez obtenir une idée de comment cela fonctionne. Sauter un peu dans vos questions, l'équivalent de List<T> est std::vector<T>, et il utilise RAII pour gérer sa mémoire. Vous pouvez utiliser quelque chose comme ceci:

void foo() {

  // declare a vector *without* using new. We want it allocated on the stack, not
  // the heap. The vector can allocate data on the heap if and when it feels like
  // it internally. We just don't need to see it in our user code
  std::vector<int> v;
  v.push_back(4);
  v.push_back(42); // Add a few numbers to it

  // And that is all. When we leave the scope of this function, the destructors 
  // of all local variables, in this case our vector, are called - regardless of
  // *how* we leave the function. Even if an exception is thrown, v still goes 
  // out of scope, so its destructor is called, and it cleans up nicely. That's 
  // also why C++ doesn't have a finally clause for exception handling, but only 
  // try/catch. Anything that would otherwise go in the finally clause can be put
  // in the destructor of a local object.
} 

Si je devais choisir un seul principe qu'un programmeur C++ doit apprendre et de s'embrasser, il est ci-dessus. Laissez-les règles de portée et les destructeurs de travail pour vous. Ils offrent toutes les garanties que vous devez écrire le code sécurisé.

La manipulation des chaînes:

std::string est votre ami. En C, vous pouvez utiliser des tableaux de char (ou pointeurs de char), mais ceux qui sont méchants, parce qu'ils ne se comportent pas comme des chaînes de caractères. En C++, vous avez une classe std::string, qui se comporte comme vous le souhaitez. La seule chose à garder à l'esprit est que "hello world" est de type char[12] et PAS de std::string. (C compatibilité), vous aurez donc parfois explicitement convertir votre chaîne littérale (quelque chose entre guillemets, comme "bonjour le monde") d'un std::string pour obtenir le comportement que vous voulez: Vous pouvez toujours écrire

std::string s = "hello world";

parce que le C-style cordes (telles que des littéraux, comme "bonjour le monde") sont implicitement convertible std::string, mais il ne fonctionne pas toujours: "bonjour" + "monde" ne compile pas, parce que l'opérateur + n'est pas défini pour les deux pointeurs. "bonjour monde" + " d " cependant, sera de la compilation, mais il ne sera pas faire quelque chose de sensé. Au lieu d'ajouter un char à une chaîne, il va prendre la valeur intégrale de la char (qui est promu à un int), et l'ajouter à la valeur du pointeur.

std::string("bonjour le monde") + "d" ne signifie que vous vous attendez cependant, parce que le côté gauche est déjà un std::string, et l'ajout de l'opérateur est surchargé pour les std::string à faire comme vous le souhaitez, même si le côté droit est un char* ou un seul caractère.

Une dernière remarque sur les chaînes: std::string utilise char, qui est un octet de type de données. Qui est, il n'est pas adapté pour le texte unicode. C++ fournit la vaste de caractères de type wchar_t qui est de 2 ou 4 octets, selon la plateforme, et est généralement utilisé pour le texte unicode (bien que dans les deux cas, la norme C++ vraiment spécifier le jeu de caractères). Et une chaîne de wchar_t est appelé std::wstring.

Bibliothèques:

Ils n'existent pas, fondamentalement. Le langage C++ n'a pas de notion de bibliothèques, et cela prend un peu pour s'y habituer. Il vous permet de #inclure un autre fichier (généralement un en-tête de fichier avec l'extension .h ou .hpp), mais c'est tout simplement un copie/coller. Le préprocesseur simplement combine les deux fichiers résultant de ce qu'on appelle une unité de traduction. Plusieurs fichiers source inclus généralement les mêmes en-têtes, et qui ne fonctionne que dans certaines circonstances particulières, si ce bit est la clé de la compréhension de la compilation C++ modèle, qui est notoirement décalé. Au lieu de compiler un tas de modules distincts, et exhanging une sorte de métadonnées entre eux, comme un compilateur C# serait, chaque unité de traduction est compilé dans l'isolement, et l'objet résultant des fichiers sont transmis à un éditeur de liens qui essaie ensuite de fusionner les parties communes de retour ensemble (si plusieurs unités de traduction inclus le même en-tête, vous disposez d'un code dupliqué sur les unités de traduction, de sorte que l'éditeur de liens fusionne de nouveau dans une définition unique) ;)

Bien sûr, il ya une plate-forme spécifique façons d'écrire des bibliothèques. Sur Windows, vous pouvez faire .dll ou .libs, avec la différence qu'un .lib est lié à votre application tout en un .dll est un fichier séparé que vous avez à combiner avec votre application, tout comme dans .NET. Sur Linux, l'équivalent types de fichiers sont .donc et .un, et dans tous les cas, vous devez présenter les fichiers d'en-tête ainsi, pour les personnes à être en mesure de développer à l'encontre de vos bibliothèques.

Conversions de types de données:

Je ne suis pas sûr exactement ce que vous cherchez là, mais un point me semble important, c'est que le "traditionnel" cast comme dans l'exemple suivant, qui est mauvais:

int i = (int)42.0f; 

Il y a plusieurs raisons à cela. Tout d'abord, il tente d'effectuer plusieurs types de distributions dans l'ordre, et vous pouvez être surpris par le compilateur finit par l'application. Deuxièmement, il est difficile de trouver dans une situation de recherche, et en troisième lieu, il n'est pas laid assez. Les castes sont généralement à éviter, et en C++, ils sont fait un peu moche pour vous rappeler de cela. ;)

// The most common cast, when the types are known at compile-time. That is, if 
// inheritance isn't involved, this is generally the one to use
static_cast<U>(T); 

// The equivalent for polymorphic types. Does the same as above, but performs a 
// runtime typecheck to ensure that the cast is actually valid
dynamic_cast<U>(T); 

// Is mainly used for converting pointer types. Basically, it says "don't perform
// an actual conversion of the data (like from 42.0f to 42), but simply take the
// same bit pattern and reinterpret it as if it had been something else). It is
// usually not portable, and in fact, guarantees less than I just said.
reinterpret_cast<U>(T); 

// For adding or removing const-ness. You can't call a non-const member function
// of a const object, but with a const-cast you can remove the const-ness from 
// the object. Generally a bad idea, but can be necessary.
const_cast<U>(T);

Comme vous pourrez le noter, ces distributions sont beaucoup plus spécifique, ce qui signifie que le compilateur peut vous donner une erreur si le casting n'est pas valide (à la différence de la syntaxe traditionnelle, où il venait de tenter tout ce qui précède jette jusqu'à en trouver un qui fonctionne), et il est grand et détaillé, vous permettant de rechercher pour elle, et vous rappelle qu'ils doivent être évités si possible. ;)

La bibliothèque standard:

Enfin, pour en revenir à des structures de données, mettre un peu d'efforts dans la compréhension de la bibliothèque standard. Elle est petite, mais étonnamment polyvalent, et une fois que vous apprendre à l'utiliser, vous serez dans une bien meilleure position.

La bibliothèque standard se compose de plusieurs assez distinctes blocs de construction (la bibliothèque a accumulé au fil du temps. Certaines parties ont été porté à partir de C. Le flux e/S de la bibliothèque sont adoptées à partir d'un seul endroit, et le conteneur des classes et de leurs fonctionnalités associées sont adoptées à partir d'un de complètement différent de la bibliothèque, et sont conçus de façon sensiblement différente. Ces derniers font partie de ce qui est souvent désigné comme la STL (Standard Template Library). Strictement parlant, c'est le nom de la bibliothèque qui, légèrement modifié, obtenu adoptée dans la Norme C++ de la Bibliothèque.

La STL est la clé de la compréhension de "modern C++". Il est composé de trois piliers, les conteneurs, les itérateurs et les algorithmes. En un mot, les conteneurs exposer les itérateurs et les algorithmes de travail sur itérateur paires.

L'exemple suivant prend un vecteur de type int, ajoute 1 à chaque élément, et la copie d'une liste liée, juste pour le plaisir d'exemple:

int add1(int i) { return i+1; } // The function we wish to apply

void foo() {
  std::vector<int> v;
  v.push_back(1);
  v.push_back(2);
  v.push_back(3);
  v.push_back(4);
  v.push_back(5); // Add the numbers 1-5 to the vector

  std::list<int> l;

  // Transform is an algorithm which applies some transformation to every element
  // in an iterator range, and stores the output to a separate iterator
  std::transform ( 
  v.begin(),
  v.end(), // Get an iterator range spanning the entire vector
  // Create a special iterator which, when you move it forward, adds a new 
  // element to the container it points to. The output will be assigned to this
  std::back_inserter(l) 
  add1); // And finally, the function we wish to apply to each element
}

Le style précédent faut s'habituer à, mais il est extrêmement puissant et concis. Parce que la fonction de transformation est basé sur un modèle, il peut accepter tous les types d'entrée, tant qu'ils se comportent comme des itérateurs. Cela signifie que la fonction peut être utilisé pour combiner n'importe quel type de conteneurs, ou même des ruisseaux ou quoi que ce soit d'autre que l'on peut parcourir à travers, aussi longtemps que l'itérateur est conçu pour être compatible avec le TSL. Nous avons également ne pas avoir à utiliser les mots begin et end. Au lieu de la fin de l'itération, on aurait pu passer de l'un pointant vers le troisième élément, et l'algorithme aurait alors arrêté là. Ou nous pourrions avoir écrit personnalisé itérateurs qui sauté tous les autres éléments, ou tout autre chose qui nous a plu. Le ci-dessus est un exemple de base de chacun des trois piliers. Nous utilisons un conteneur pour stocker les données, mais l'algorithme que nous utilisons pour traiter, il n'est pas réellement nécessaire de savoir sur le conteneur. Il a juste à savoir à propos de l'itérateur de gamme sur lequel il doit travailler. Et bien sûr, chacun de ces trois piliers peut être étendu par l'écriture de nouvelles classes, ce qui permettra ensuite de travailler en douceur avec le reste de la STL.

Dans un sens, c'est très similaire à LINQ, donc, puisque vous venez de .NET, vous pouvez probablement voir certaines analogies. La STL homologue est un peu plus souple si, au coût d'un peu plus étranges de la syntaxe. :) (Comme mentionné dans les commentaires, il est aussi plus efficace. En général, il y a zéro des frais généraux aux algorithmes de la STL, ils peuvent être tout aussi efficaces que les codée à la main boucles. C'est souvent étonnant, mais il est possible que parce que tous les types sont connus au moment de la compilation (ce qui est une exigence pour les modèles de travail), et les compilateurs C++ ont tendance à inline agressivement.)

3voto

Brian Points 2013

Vous avez des boîtes à outils disponibles. Par exemple, il y a de la STL (Standard Template Library) et Boost/TR1 (extensions STL) qui sont considérés comme les normes de l'industrie (ainsi, la STL est, au moins). Ceux-ci fournissent des listes, des cartes, jeux, partagé des pointeurs, des cordes, des ruisseaux, et toutes sortes d'autres outils pratiques. Le meilleur de tous, ils sont largement pris en charge par les compilateurs.

Comme pour les conversions de données, vous pouvez soit faire des moulages ou créer explicite les fonctions du convertisseur.

Bibliothèques - Vous pouvez créer des bibliothèques statiques (obtenir absorbée dans l'exécutable final) ou des Dll (vous êtes familier avec ces, déjà). MSDN est une formidable ressource pour les Dll. Les bibliothèques statiques dépendent de votre environnement de construction.

En général, c'est mon avis: - Apprenez à connaître votre IDE de choix très bien - Achat "C++ La Référence Complète" par Herbert Schildt, que je considère être un excellent tome sur toutes les choses C++ (comprend STL)

Compte tenu de vos antécédents, vous devriez être bien définie une fois que vous faites tous les deux de ceux-ci.

3voto

Electrons_Ahoy Points 6972

Je ne vais pas répéter ce que les autres ont dit à propos des bibliothèques et tels, mais si vous êtes sérieux au sujet de C++, ne vous une faveur et ramasser Bjarne Stroustrup "Le Langage de Programmation C++."

Il m'a fallu des années de travail en C++ pour enfin prendre une copie, et une fois que je l'ai fait, j'ai passé un après-midi de gifler mon front en disant: "bien sûr! Je devrais l'avoir réalisé! etc."

(Ironie du sort, j'ai eu EXACTEMENT la même expérience avec le K&R "The C Programming Language". Un jour, je vais apprendre à juste aller chercher "Le Livre" le jour 1.)

1voto

rmeador Points 15107

Le référencement et l'utilisation d'autres bibliothèques, si vous êtes, y compris la source, se fait tout simplement par #, y compris les fichiers d'en-tête de la bibliothèque en quoi que ce soit .rpc fichier dont vous avez besoin (et puis compiler le code source de la bibliothèque avec votre projet). La plupart du temps, cependant, vous serez probablement en utilisant un .lib (bibliothèque statique) ou .dll (dynamic library). La plupart (tous?) Dll venir avec un .fichier lib, donc la procédure pour les deux types est la même: d'inclure les fichiers d'en-tête où vous en avez besoin, puis ajouter les associés .fichier lib lors de l'étape de liaison (dans visual studio, je pense que vous pouvez simplement ajouter le fichier au projet).

Il a été un long temps depuis que j'ai créé mon propre bibliothèques à utiliser pour les autres, donc je vais laisser quelqu'un d'autre réponse que de la partie. Ou je vais revenir et modifier cette réponse demain, car je vais créer une .lib pour le travail de demain :)

Chaîne de choses est généralement réalisé avec des std::string. Dans des circonstances spéciales, vous pouvez également utiliser l'ancien style C fonction sprintf (), mais c'est généralement déconseillée.

Aussi loin que les structures de données que vous cherchez, consultez la STL (Standard Template Library). Il comprend la Liste, Vecteur, Carte, String, etc qui devrait vous être familière. Je ne suis pas sûr de ce que vous entendez par les conversions de type... je suppose que vous savez au sujet du casting, si vous devez dire quelque chose de plus complexe que ça, dans ce cas, c'est probablement spécifique pour les types que vous essayez de convertir. Peut-être quelqu'un d'autre peut offrir plus d'infos.

0voto

Tamir Points 1314

J'ai écrit un petit aide-mémoire pour de tels programmeurs. Vous pouvez également être intéressé par des cas plus complexes, tels que varargs

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X