web-dev-qa-db-fra.com

Java final vs C ++ const

Le tutoriel pour les programmeurs Java pour C++ dit que (le surlignage est le mien):

Le mot-clé final est plus ou moins équivalent à const en C++

Que signifie "grossièrement" dans ce contexte? Ne sont-ils pas exactement identiques?

Quelles sont les différences, le cas échéant?

143
WinWin

En C++, marquer une fonction membre const signifie qu'elle peut être appelée sur const instances. Java n'a pas d'équivalent à ceci. E.g .:

class Foo {
public:
   void bar();
   void foo() const;
};

void test(const Foo& i) {
   i.foo(); //fine
   i.bar(); //error
}

Les valeurs peuvent être affectées, une fois, ultérieurement dans Java uniquement, par exemple:

public class Foo {
   void bar() {
     final int a;
     a = 10;
   }
}

est légal en Java, mais pas en C++ alors que:

public class Foo {
   void bar() {
     final int a;
     a = 10;
     a = 11; // Not legal, even in Java: a has already been assigned a value.
   }
}

Dans les deux Java et variables de membre C++ peuvent être respectivement final/const. _. Il faut leur donner une valeur au moment où une instance de la classe est terminée.) en cours de construction.

Dans Java ils doivent être définis avant la fin du constructeur, ceci peut être réalisé de l'une des deux manières suivantes:

public class Foo {
   private final int a;
   private final int b = 11;
   public Foo() {
      a = 10;
   }
}

En C++, vous devrez utiliser les listes d'initialisation pour donner à const members une valeur:

class Foo {
   const int a;
public:
   Foo() : a(10) {
      // Assignment here with = would not be legal
   }
};

Dans Java final peut être utilisé pour marquer des éléments comme étant non substituables. C++ (pré-C++ 11) ne le fait pas.

public class Bar {
   public final void foo() {
   }
}

public class Error extends Bar {
   // Error in Java, can't override
   public void foo() {
   }
}

Mais en C++:

class Bar {
public:
   virtual void foo() const {
   }
};

class Error: public Bar {
public:
   // Fine in C++
   virtual void foo() const {
   }
};

c'est très bien, car la sémantique de marquer une fonction membre const est différente. (Vous pouvez aussi surcharge si vous n’avez que const sur l’une des fonctions membres. (Notez également que C++ 11 permet de marquer les fonctions membres comme final, voir C++ 11 section de mise à jour)


Mise à jour C++ 11:

C++ 11 vous permet en fait de marquer les classes et les fonctions membres comme final, avec une sémantique identique à la même fonctionnalité en Java, par exemple en Java:

public class Bar {
   public final void foo() {
   }
}

public class Error extends Bar {
   // Error in Java, can't override
   public void foo() {
   }
}

Peut maintenant être écrit exactement en C++ 11 en tant que:

class Bar {
public:
  virtual void foo() final;
};

class Error : public Bar {
public:
  virtual void foo() final;
};

J'ai dû compiler cet exemple avec une pré-version de G ++ 4.7. Notez que cela ne remplace pas const dans ce cas, mais l'augmente, en fournissant le comportement semblable à Java qui n'a pas été vu avec le mot clé C++ équivalent le plus proche. Donc si vous voulez qu'une fonction membre soit à la fois final et const, vous feriez:

class Bar {
public:
  virtual void foo() const final;
};

(L'ordre de const et final est requis ici).

Auparavant, il n'y avait pas d'équivalent direct de const fonctions membres, bien que créer des fonctions non -virtual soit une option potentielle, sans toutefois générer d'erreur au moment de la compilation.

De même le Java:

public final class Bar {
}

public class Error extends Bar {
}

devient en C++ 11:

class Bar final {
};

class Error : public Bar {
};

(Auparavant, private constructeurs était probablement le plus proche de celui-ci en C++)

Il est intéressant de noter que pour maintenir la compatibilité avec le code antérieur à C++ 11, finaln’est pas un mot clé de la manière habituelle. (Prenons l'exemple trivial et légal C++ 98 struct final; pour voir pourquoi en faire un mot clé casserait le code)

183
Flexo

Dans Java, le mot-clé final peut être utilisé pour quatre choses:

  • sur une classe ou une méthode pour la sceller (aucune sous-classe/dérogation autorisée)
  • sur une variable membre pour déclarer que cela peut être défini exactement une fois (je pense que c'est de cela dont vous parlez)
  • sur une variable déclarée dans une méthode, pour s'assurer qu'elle peut être définie exactement une fois
  • sur un paramètre de méthode, pour déclarer qu'il ne peut pas être modifié dans la méthode

Une chose importante est: A Java La variable membre finale doit être doit être définie exactement une fois! Par exemple, dans un constructeur, une déclaration de champ ou un intializer. (Mais vous ne pouvez pas définir une variable membre finale dans une méthode).

Une autre conséquence de la création d'une variable membre finale concerne le modèle de mémoire, ce qui est important si vous travaillez dans un environnement thread.

29
Ralph

Un objet const ne peut appeler que des méthodes const et est généralement considéré comme immuable.

const Person* person = myself;
person = otherPerson; //Valid... unless we declared it const Person* const!
person->setAge(20); //Invalid, assuming setAge isn't a const method (it shouldn't be)

Un objet final ne peut pas être défini sur un nouvel objet, mais il n'est pas immuable - rien n'empêche quelqu'un d'appeler une méthode set.

final Person person = myself;
person = otherPerson; //Invalid
person.setAge(20); //Valid!

Java n'a aucun moyen inhérent de déclarer des objets immuables; vous devez concevoir la classe comme immuable vous-même.

Lorsque la variable est un type primitif, final/const fonctionne de la même manière.

const int a = 10; //C++
final int a = 10; //Java
a = 11; //Invalid in both languages
25

Java final est équivalent à C++ const sur les types de valeur primitifs.

Avec les types de référence Java), le mot-clé final est équivalent à un pointeur const ... c'est-à-dire.

//Java
final int finalInt = 5;
final MyObject finalReference = new MyObject();

//C++
const int constInt = 5;
MyObject * const constPointer = new MyObject();
12
James Schek

Vous avez déjà quelques bonnes réponses ici, mais un point qui semblait intéressant d’être ajouté: const en C++ est couramment utilisé pour empêcher d’autres parties du programme de modifier l’état des objets. Comme il a été souligné, final in Java ne peut pas faire cela (sauf pour les primitives) - cela empêche simplement le passage de la référence à un autre objet, mais si vous utilisez un Collection, vous pouvez empêcher toute modification de vos objets en utilisant la méthode statique

 Collection.unmodifiableCollection( myCollection ) 

Cela retourne une référence Collection qui donne un accès en lecture aux éléments, mais lève une exception si des modifications sont tentées, ce qui le rend un peu comme const en C++.

8
pocketdora

La méthode final de Java ne fonctionne que sur les types primitifs et les références, jamais sur les instances d'objet elles-mêmes où le mot clé const fonctionne sur quoi que ce soit.

Comparer const list<int> melist; avec final List<Integer> melist; le premier rend impossible la modification de la liste, tandis que le dernier ne vous empêche pas d'attribuer une nouvelle liste à melist.

7
josefx

En plus d'avoir certaines et subtiles propriétés multi-threading , les variables déclarées final n'ont pas besoin d'être initialisé sur déclaration!

c'est-à-dire valide en Java:

// declare the variable
final int foo;

{
    // do something...

    // and then initialize the variable
    foo = ...;
}

Cela ne serait pas valable si écrit avec C++ const.

3
antak

Selon wikipedia :

  • En C++, non seulement un champ const est protégé contre la réaffectation, mais il existe une limitation supplémentaire: seules les méthodes const peuvent y être appelées et il ne peut être passé que comme argument const.
  • Les classes internes non statiques peuvent accéder librement à tout champ de la classe englobante, final ou non.
2
KevenK

Je suppose que cela dit "à peu près" parce que la signification de const en C++ se complique lorsque vous parlez de pointeurs, c’est-à-dire des pointeurs constants ou des pointeurs sur des objets constants. Comme il n'y a pas de pointeurs "explicites" en Java, final n'a pas ces problèmes.

2
Dima

Permettez-moi d’expliquer ce que j’ai compris avec un exemple de déclaration de substitution.

Les valeurs de chaque instruction case doivent être des valeurs constantes au moment de la compilation du même type de données que la valeur du commutateur.

déclarez quelque chose comme ci-dessous (soit dans votre méthode en tant qu'instances locales, soit dans votre classe en tant que variable statique (ajoutez-y ensuite une valeur statique), ou une variable d'instance.

final String color1 = "Red";

et

static final String color2 = "Green";

switch (myColor) { // myColor is of data type String
    case color1:
    //do something here with Red
    break;
    case color2:
    //do something with Green
    break;
}

Ce code ne sera pas compilé si color1 est une variable de classe/instance et non une variable locale. Cela compilera si color1 est défini comme final statique (il devient alors variable finale statique).

Quand il ne compile pas, vous obtiendrez l'erreur suivante

error: constant string expression required
0
Subbu Mahadevan