Où mettre la valeur du paramètre par défaut en C++? [dupliquer]
Cette question a déjà une réponse ici:
- valeur par défaut du paramètre de fonction 4 réponses
Quelle est la place pour la valeur du paramètre par défaut? Juste dans la définition de la fonction, ou la déclaration, ou les deux endroits?
10 réponses
Les valeurs des paramètres par défaut doivent apparaître sur la déclaration, car c'est la seule chose que l'appelant voit.
EDIT:, Comme l'autre, vous peut l'argument sur la définition, mais je vous conseille d'écrire tout le code comme si ce n'était pas vrai.
Vous pouvez faire l'un ou l'autre, mais jamais les deux. Habituellement, vous le faites à la déclaration de fonction et tous les appelants peuvent utiliser cette valeur par défaut. Cependant vous pouvez le faire à la définition de la fonction à la place et seuls ceux qui voient la définition pourront utiliser la valeur par défaut.
L'endroit le plus utile est dans la déclaration (.h) afin que tous les utilisateurs le voient.
Certaines personnes aiment aussi ajouter les valeurs par défaut dans l'implémentation (en commentaire):
void foo(int x = 42,
int y = 21);
void foo(int x /* = 42 */,
int y /* = 21 */)
{
...
}
Cependant, cela signifie une duplication et ajoutera la possibilité d'avoir le commentaire désynchronisé avec le code (qu'est-ce qui est pire que le code non commenté? code avec des commentaires trompeurs!).
Bien que ce soit un "vieux" thread, je voudrais toujours ajouter ce qui suit:
J'ai connu le cas suivant:
- dans le fichier d'en-tête d'une classe, j'avais
int SetI2cSlaveAddress( UCHAR addr, bool force );
- dans le fichier source de cette classe, j'avais
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force = false ) { ... }
Comme on peut le voir, j'avais mis la valeur par défaut du paramètre "force" dans le fichier source de la classe, pas dans le fichier d'en-tête de classe.
Ensuite, j'ai utilisé cette fonction dans une classe dérivée comme suit (classe dérivée héritée de la classe de base de manière publique):
SetI2cSlaveAddress( addr );
En supposant qu'il prendrait le paramètre "force" comme " false "' pour acquis'.
Cependant, le compilateur (mettre en mode c++11) s'est plaint et m'a donné l'erreur de compilateur suivante:
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp: In member function 'void CMax6956Io::Init(unsigned char, unsigned char, unsigned int)':
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: error: no matching function for call to 'CMax6956Io::SetI2cSlaveAddress(unsigned char&)'
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: note: candidate is:
In file included from /home/geertvc/mystuff/domoproject/lib/i2cdevs/../../include/i2cdevs/max6956io.h:35:0,
from /home/geertvc/mystuff/domoproject/lib/i2cdevs/max6956io.cpp:1:
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: int CI2cHal::SetI2cSlaveAddress(unsigned char, bool)
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: candidate expects 2 arguments, 1 provided
make[2]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/max6956io.cpp.o] Error 1
make[1]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/all] Error 2
make: *** [all] Error 2
, Mais quand j'ai ajouté le paramètre par défaut dans le l'en-tête fichier de la classe de base:
int SetI2cSlaveAddress( UCHAR addr, bool force = false );
Et l'a retiré du fichier source de la classe de base:
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force )
Alors le compilateur était heureux et tout le code fonctionnait comme prévu (je pouvais donner un ou deux paramètres à la fonction SetI2cSlaveAddress()
)!
Donc, non seulement pour l'utilisateur d'une classe, il est important de mettre la valeur par défaut d'un paramètre dans le fichier d'en-tête, également la compilation et fonctionnel sage apparemment, il semble être un must!
Si les fonctions sont exposées-non-membre, public ou protégé-alors l'appelant doit les connaître, et les valeurs par défaut doivent ÊTRE dans l'en-tête.
Si les fonctions sont privées et hors ligne, il est logique de placer les valeurs par défaut dans le fichier d'implémentation car cela permet des modifications qui ne déclenchent pas la recompilation du client (un problème parfois sérieux pour les bibliothèques de bas niveau partagées dans le développement à l'échelle de l'entreprise). Cela dit, il est certainement potentiellement déroutant, et il y a une valeur de documentation dans la présentation de l'API d'une manière plus intuitive dans l'en - tête, alors choisissez votre compromis-bien que la cohérence soit la chose principale quand il n'y a aucune raison impérieuse de toute façon.
La déclaration est généralement le plus "utile", mais cela dépend de comment vous voulez utiliser la classe.
Les deux ne sont pas valides.
Bonne question... Je trouve que les codeurs utilisent généralement la déclaration pour déclarer les valeurs par défaut. J'ai été tenu d'une manière (ou averti) ou l'autre aussi basé sur le compilateur
void testFunct(int nVal1, int nVal2=500);
void testFunct(int nVal1, int nVal2)
{
using namespace std;
cout << nVal1 << << nVal2 << endl;
}
Un point de plus, je n'ai trouvé personne mentionné:
Si vous avez une méthode virtuelle, chaque déclaration peut avoir sa propre valeur par défaut!
Cela dépend de l'interface que vous appelez quelle valeur sera utilisée.
Exemple sur ideone
struct iface
{
virtual void test(int a = 0) { std::cout << a; }
};
struct impl : public iface
{
virtual void test(int a = 5) override { std::cout << a; }
};
int main()
{
impl d;
d.test();
iface* a = &d;
a->test();
}
, Il imprime 50
Je vous déconseillons fortement de l'utiliser comme ceci
Vous pouvez le faire dans l'un ou l'autre(selon standard), mais rappelez-vous, si votre code voit la déclaration sans argument par défaut avant la définition qui contient l'argument par défaut, alors l'erreur de compilation peut arriver.
Par exemple, si vous incluez une déclaration de fonction contenant un en-tête sans liste d'arguments par défaut, le compilateur recherchera ce prototype car il ignore les valeurs de vos arguments par défaut et, par conséquent, le prototype ne correspondra pas.
Si vous mettez la fonction avec argument par défaut dans la définition, puis incluez ce fichier mais je ne le suggérerai pas.
Ajouter un point de plus. Les déclarations de fonction avec argument par défaut doivent être ordonnées de droite à gauche et de haut en bas.
Par exemple dans la déclaration de fonction ci-dessous si vous modifiez l'ordre de déclaration, le compilateur vous donne une erreur de paramètre par défaut manquante. Raison le compilateur vous permet de séparer la déclaration de fonction avec l'argument par défaut dans la même portée, mais il devrait être dans l'ordre de droite à gauche (arguments par défaut) et de haut en bas(ordre de l'argument par défaut de la déclaration de fonction).
//declaration
void function(char const *msg, bool three, bool two, bool one = false);
void function(char const *msg, bool three = true, bool two, bool one); // Error
void function(char const *msg, bool three, bool two = true, bool one); // OK
//void function(char const *msg, bool three = true, bool two, bool one); // OK
int main() {
function("Using only one Default Argument", false, true);
function("Using Two Default Arguments", false);
function("Using Three Default Arguments");
return 0;
}
//definition
void function(char const *msg, bool three, bool two, bool one ) {
std::cout<<msg<<" "<<three<<" "<<two<<" "<<one<<std::endl;
}