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?
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)
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, final
n’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)
Dans Java, le mot-clé final peut être utilisé pour quatre choses:
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.
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
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();
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++.
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
.
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
.
Selon wikipedia :
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.
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