Developpez.com - Microsoft DotNET
X

Choisissez d'abord la catégorieensuite la rubrique :

Migrer du C++ au C#

Mis à jour le 27/11/2002

Par Leduke 

Droit de diffusion:
L'ensemble ou partie de ce document ainsi que le code mis à disposition, ne peut être diffusé sur d'autres sites Web sans l'autorisation au préalable de son créateur.

Certaines parties de cet article sont extraites de l'article : "C++ -> C#: What You Need to Know to Move from C++ to C#" de Jesse Liberty.

Avant Propos :
Ce document a pour but de présenter les principales différences entre le C++ et le C# et d'aider les personnes désireuses de réaliser le portage d'une application C++ en C#.

 

Sommaire:

Introduction
1. Les pièges
2. Les principales différences entre le C++ et le C#
3. Les types de valeur et de référence
4. Les structures
5. Tout dérive de la classe Object
6. La gestion des paramètres des prototypes de fonctions
7. Le mot clé "new"
8. Les propriétés
9. Les tableaux
Conclusion

 

 

Introduction

Le langage C# s'appuit sur la syntaxe et la sémantique du C++, permettant au programmeur C de bénéficier des avantages de .NET et de la Common Language Runtime. Alors que la transition du C++ vers le C# peut paraître aisée, il y a un certain nombre d'éléments qui ont changé que nous allons étudier tels que l'opérateur new, les structures, les constructeurs, les destructeurs.

1. Pièges

Le langage C# ressemble à s'y méprendre au C++. Il se peut que vous écriviez du code qui est parfaitement correct en C++ mais qui ne compile pas en C# ou au pire ne se comporte pas à l'exécution comme vous l'attendiez.  La plupart des différences syntaxiques entre le C++ et le C# sont triviales (pas de point virgule après la déclaration d'une classe, Main comporte désormais une majuscule) et sont détectées par le compilateur.

2. Les principales différences entre le C++ et le C#

Fonctionnalité Documentation de référence

Héritage : Une classe peut hériter de l'implémentation d'une seule classe de base uniquement. Une classe ou une interface peuvent implémenter plusieurs interfaces.

class

interface

Tableaux: La déclaration d'un tableau en C# est différente de celle en C++. Les crochets  "[]" doivent apparaître à la suite du type de tableau en C#. Arrays
Le type bool: Il n'existe pas de conversion entre le type  bool et d'autres types (particulièrement  int). bool
Le type  long :  En  C#, le type de données long est sur 64 bits alors qu'il est sur 32 bits en C++. long
Le type struct  : En C#, les classes et les structures sont sémantiquement différents. Une structure est un type de valeur alors qu'une classe est un type de reference. struct

class

L'instruction switch : Comparativement au C++, le C# n'autorise pas le passage automatique à chaque condition d'une clause switch. switch
Le type  delegate : Les delegates ressemblent à des pointeurs de fonctions mais ils sont sécurisés et fortement typés. delegate

Appel d'une fonction membre d'une classe surchargée à partir d'une classe dérivée.

base

Voir aussi les exemples pour override

Utilisation du mot clé New afin de cacher explicitement une fonction héritée.

new

La surcharge d'une méthode nécessite l'utilisation du mot clé override

override

Les directives de préprocessing sont utilisées pour la compilation conditionnelle. Il n'y pas de fichier includes en C#.

C# Preprocessor Directives
La gestion des exceptions: L'utilisation de la clause  finally. try-finally

try-catch-finally

Les opérateurs C# : Le C# comporte des opérateurs supplémentaires tels que  is et typeof ainsi que des fonctionnalités différentes de certains opérateurs logiques. & Operator

| Operator

^ Operator

is

typeof

L'utilisation du mot clé extern extern
L'utilisation du mot clé static static

Une solution alternative à la liste d'initialisation C++ dans la construction d'une classe de base.

Voir les exemples pour  virtual
La structure générale d'un programme C#: les espaces de noms, les classes, les structures, les delegates, les énumérations. General Structure of a C# Program

La déclaration de la méthode Main diffère de celle en C++ mais aussi la manipulation des arguments passés en ligne de commande.

Main
Les paramètres des méthodes: Le C# supporte les mots réservés  ref et out , qui sont utilisés à la place de pointeurs pour le passage de paramètre par référence. ref

out

Les pointeurs sont autorisés en C# mais seulement dans un mode dit "unsafe". unsafe
La surcharge d'opérateurs est différente en C# C# Operators
Les chaînes de caractères C# sont différentes de celles en C++ string

Le mot clé foreach permet de parcourir des tableaux et des collections.

foreach, in
Il n'existe pas de méthodes ou de variables globales en C#: Les méthodes et les variables doivent être contenues dans la portée d'une déclaration (tel qu'une classe ou une structure) General Structure of a C# Program

Il n'existe pas de fichiers entêtes ou de directives d'inclusions en C#: Le mot clé using est utilisé pour référencer des espaces de noms.

using
Les variables locales en C# ne peuvent être utilisées sans avoir été initialisées au préalable. 5. Variables
Les destructeurs : En C# il n'est pas possible de maîtriser l'appel de destructeurs car ceux-ci sont appelés automatiquement par le ramasse miettes (garbage collector). Destructors
Les constructeurs: Comparativement au C++, si vous ne fournissez pas un constructeur, un constructeur par défaut est automatiquement généré. Celui-ci se charge d'initialiser tous les champs avec leurs valeurs par défaut. Instance Constructors

Default Values Table.

Le C# ne supporte pas les champs de type "bit".

C++ Bit Fields

Les services d'entrée/sortie et de formattage de données s'appuient sur le RunTime du Framework .NET.

C# Language Tour

Formatting Numeric Results Table

En C# les paramètres des méthodes ne peuvent avoir de valeur par défaut. Il faut surcharger les méthodes pour obtenir ce résultat. Compiler Error CS0241

 

3. Les types de valeur et de référence

Le C# distingue les types de valeur (value) des types de référence (reference). Les types simples (int, long, double ...) et les structures sont des types de valeurs alors que les classes sont des types de référence tout comme les objets. Les types value représentent la donnée réelle stockée sur la pile et sont passés aux méthodes par valeur (une copie est réalisée). Les types reference contiennent l'adresse d'un objet stocké sur le tas et sont passés en paramètre par référence.

4. Les structures

Les structures sont différentes en C#. En C++ les structures sont exactement comme une classe, sauf que l'héritage et l'accès par défaut est public et non privé. En C# les structures sont conçues pour encapsuler de petits objets et sont de type value (donc passées par valeur). Elles sont limitées dans la mesure où elles ne peuvent dériver d'aucune classe sauf System.ValueType et qu'elles ne peuvent pas définir de constructeur par défaut (sans paramètres). En contre partie l'utilisation d'une structure est préférable à celui d'une classe pour de trés petits objets.

5. Tout dérive de la classe Object

En C# finalement tout dérive de la classe Object aussi bien les classes que vous créez que les types de valeurs (int, struct ...). La classe Object présente des méthodes utiles comme la méthode ToString. Prenons un exemple d'utilisation de la méthode ToString et de la méthode System.Console.WriteLine (équivalent du cout en C++). Considérons un objet myEmployee comme instance de l'objet Employee et un objet myCounter comme instance de l'objet Counter. Si nous écrivons le code suivant :

Console.WriteLine("The employee: {0}, the counter value: {1}", myEmployee, myCounter);

La méthode WriteLine va appeler la méthode virtuelle Objet.ToString de chacun de ces objets et substituer les chaînes que les paramètres vont retourner. Si la classe Employee ne surcharge pas la méthode ToString l'implémentation par défaut sera appelée laquelle retourne le nom de la classe. La classe Counter va surcharger la méthode ToString afin de retourner un entier ce qui produit à l'exécution le résultat suivant :

The employee: Employee, the counter value: 12

Que se passe-t-il si l'on transmet à la méthode WriteLine un entier ? Il n'est pas possible d'appeler la méthode ToString sur un entier mais le compilateur va implicitement transformer l'entier en une instance de l'objet Object dont la valeur sera celle de l'entier. Cette transformation porte le terme de boxing.

Vous trouverez ci-joint l'exemple complet.

using System;
// Une classe qui ne surcharge pas la méthode ToString


public class Employee
{
}
// Une classe qui surcharge la méthode ToString
public class Counter
{
    private int theVal;
    public Counter(int theVal)
    {
         this.theVal = theVal;
    }
    public override string ToString()
    {
        Console.WriteLine("Calling Counter.ToString()"); return theVal.ToString();
    }
}


public class Tester()
{
    // A noter que la fonction Main contient une majuscule et que c'est une fonction membre de la classe 
    public static void Main() 
    {
        // Création d'une instance de la classe
        Tester t = new Tester();
        t.Run();
    }
    // La méthode Run présente l'opération ToString et le boxing en C#
    public void Run()
    {
        Employee myEmployee = new Employee();
        Counter myCounter = new Counter(12);
        Console.WriteLine("The employee: {0}, the counter value: {1}",myEmployee, myCounter);
        // A noter que l'entier et les variables suivent une opération de boxing
       int myInt = 5;
        Console.WriteLine("Here are two integers: {0} and {1}", 17, myInt);
    }
}

6. La gestion des paramètres des prototypes de fonctions

En C# comme en C++ une méthode ne peut avoir qu'une seule valeur en retour. Pour pallier à cette limitation en C++ les paramètres sont passés par références ou via des pointeurs. La méthode appelée change la valeur des paramètres et les rend accessibles à la méthode appelante. En C# quand vous passez une référence à une méthode vous avez accès à l'objet d'origine, comme en C++ avec le passage par référence ou les pointeurs. En revanche cela ne fonctionne pas avec les types de valeurs. Si vous souhaitez passer un type de valeur par reference alors il faut le faire précéder du mot clé ref.

public void GetStats(ref int age,ref int ID,ref int yearsServed)

Il est important de préciser que le mot réservé ref doit être utilisé aussi bien dans la déclaration de la méthode que dans la méthode appelante.

Fred.GetStats(ref age, ref ID,ref yearsServed);

Vous pouvez maintenant déclarer les champs age,ID,yearsServed dans la méthode appelante et les passer à la méthode GetStats et récupérer les valeurs modifiées en retour.

En  C# il est nécessaire d'initialiser les variables avant de les passer à la méthode GetStats (definite assignment). Il est possible d'éviter cette initialisation en utilisant le mot clé out. En utilisant le mot clé out  en C#, vous indiquez que la variable n'est pas initialisée et qu'elle est passée par référence.

Fred.GetStats(out age, out ID,out yearsServed);

Comme lors de l'utilisation du mot clé ref, le mot clé out doit être utilisé aussi bien dans la déclaration de la méthode que dans la méthode appelante.

Fred.GetStats(out age,out ID,out yearsServed);

7. Le mot clé "new"

En C++, le mot clé New instancie un objet sur le tas. Le langage C# fait de même avec les types de reference. Pour les types de valeurs comme les structures, l'objet est créé sur la pile et un constructeur est appelé.

Vous pouvez aussi créer une structure sur la pile sans utiliser le mot clé New, mais attention car New initialise l'objet. Ce qui veut dire que toutes les valeurs de structure doivent être initialisées à la main (avant le passage à une méthode).

using System;
// Une structure simple avec 2 variables membres et un constructeur
public struct Point
{
    public Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
    public int x;
   public int y; 
}


public class
Tester
{
    public static void Main()
    {
        Tester t = new Tester();
        t.Run();
    }
    public void Run()
    {
        Point p1 =new Point (5, 12);
        SomeMethod (p1);
        Point p2;
        // Création sans appeler la méthode New 
    // Ce code ne compilera pas car les variables de p2 n'ont pas été initialisées
    //SomeMethod(p2);
    // Initialisation des variables manuellement

        p2.x = 1;
        p2.y = 2; 
        SomeMethod(p2); 
    } 
     private void SomeMethod(Point p)
    {
        Console.WriteLine("Point at {0} x {1}",p.x, p.y);
    }
}

8. Les propriétés

En C++, les programmeurs essaient de garder les variables membres privées. C'est le principe même de l'encapsulation qui permet de modifier l'implémentation d'une classe sans en changer l'interface. Concrètement, le développeur C++ va créer des accesseurs permettant de modifier les valeurs de variables membres privées.

En C#, les propriétés sont les premiers membres d'une classe. Pour un client, une propriété ressemble à une variable membre mais pour le développeur de la classe il s'agit plutôt d'une méthode. Les propriétés favorisent  l'encapsulation et offrent au client un accès facilité aux membres de la classe.

Par exemple considérons une classe Employee avec une propriété Age permettant à un client de valoriser ou d'extraire l'age d'une employé.

public int Age
{
    get
    {
       return age;
    }
    set
    {
        age = value;
    }
}

Le mot clé value  est défini implicitement au travers de la propriété. Si vous écrivez

Fred.Age = 17;

le compilateur va attribuer à value la valeur 17.

Il est possible d'implémenter une propriété en lecture seule, il suffit de ne pas implémenter d'accesseur Set .

public int YearsServed
{
    get
    { 
    return
 yearsServed;
    }
}

9. Les tableaux

Le C# propose une classe de gestion des tableaux plus complète que le tableau traditionnel C/C++. Par exemple, il est impossible d'écrire en dehors des limites d'un tableau. De plus C# propose une classe ArrayList dont la taille peut grossir dynamiquement en fonction des besoins du programme.

Il existe trois types de tableaux : unidimensionnel, multidimensionnel et des tableaux de tableaux (jagged array).

Vous pouvez créer un tableau à une dimension de la manière suivante :

int[] myIntArray = new int[5];

ou l'initialiser ainsi :

int[] myIntArray = { 2, 4, 6, 8, 10 };

Vous pouvez créer un tableau à deux dimensions de la manière suivante :

int[,] myRectangularArray = new int[rows, columns];

ou l'initialiser ainsi :

int[,] myRectangularArray = { {0,1,2}, {3,4,5}, {6,7,8}, {9,10,11} };

Comme les jagged array sont des tableaux de tableaux il est nécessaire de fournir uniquement une seule dimension.

int[][] myJaggedArray = new int[4][];

et ensuite de créér chacun des tableaux internes : 

myJaggedArray[0] = new int[5];
myJaggedArray[1] = new int[2];
myJaggedArray[2] = new int[3];
myJaggedArray[3] = new int[5];

Parce que les tableaux dérivent de l'objet System.Array, ils disposent de nombreuses méthodes parmis lesquelles Sort et Reverse .

 

Conclusion

A travers cet article nous avons abordé les principales différences entre le C# et le C++. Il en ressort que le passage au C# pour un développeur C++ expérimenté devrait se faire sans trop de difficultés la syntaxe se rapprochant beaucoup entre ces deux langages. Attention toutefois à ne pas tomber dans la facilité et à programmer en C# comme vous le feriez en C++ au risque d'avoir des comportements inattendus.

Remarque :
Il est tout à fait possible qu'il y ait des erreurs dans le document. Si vous en trouvez, ou bien souhaitez un peu plus d'explication sur certains points, veuillez m'envoyer un message privé via le forum afin de mettre à jour l'ensemble de ce document. D'avance merci.

Document réalisé par Leduke


Responsable bénévole de la rubrique Microsoft DotNET : Hinault Romaric -