web-dev-qa-db-fra.com

paramètres par défaut dans les fichiers .h et .cpp

COMPILATEUR: g ++ 4.7.2

D'accord. Je suis donc confus au sujet des paramètres par défaut dans les fichiers .h Et .cpp. Il est mentionné à de nombreux endroits (y compris sur ce site) que les paramètres par défaut ne peuvent être ajoutés que dans les fichiers .h et non dans les fichiers .cpp. Cependant, ce code le prouve mal:

test1.h

#pragma once

#include <iostream>
using namespace std;

class Class{
public:
    Class(int, int, int=1);
};

test1.cpp

#include "test1.h"

Class::Class(int a, int b=2, int c)
{
    cout<<a<<" "<<b<<" "<<c<<endl;
}

int main()
{
    Class a(1);
    return 0;
}

Maintenant, selon ce que j'ai testé, des paramètres par défaut peuvent être ajoutés aux fichiers .cpp. Cependant, les restrictions suivantes s'appliquent:

  1. Les paramètres par défaut présents dans les fichiers .cpp Et .h Ne doivent pas se chevaucher. c'est-à-dire Class(a, b, c=1) (dans le fichier .h) et Class::Class(a,b,c=2) (dans le fichier .cpp) n'est pas valide.

    C'est une règle bien connue qu'une fois les paramètres par défaut ajoutés, toutes les variables déclarées après doivent également contenir des valeurs par défaut. Appelons cela la règle defpara . Maintenant,

  2. Les variables indiquées dans la déclaration de fonction (fichier .h) Doivent obéir à la règle defpara c'est-à-dire Class(a, b=2, c) (in. h file) est invalide indépendamment de ce qui est déclaré dans le fichier .cpp.

  3. Si l'on considère les variables ayant des valeurs par défaut (comme une intersection de valeurs par défaut dans les fichiers .h Et .cpp), Il suivra le defpara règle. c'est-à-dire Class(a, b, c=1) (dans le fichier .h) et Class::Class(a,b=2,c) (dans le fichier .cpp) est valide. Mais Class(a, b, c=1) (dans le fichier .h) et Class::Class(a=2,b,c) (dans le fichier .cpp) N'est pas valide.

Alors .... j'ai raison, tort ???

30
sudeepdino008

Cela ne fonctionne que parce que votre fonction principale se trouve également dans votre test.cpp fichier, donc il voit l'argument par défaut spécifié dans l'implémentation de votre classe. Si vous placez votre fonction main dans un fichier séparé qui ne comprend que test.h, ce code ne sera pas compilé.

Une autre façon de voir les choses est, quand une autre comprend test.h, tout ce que le code voit est ce qui est déclaré dans test.h, donc les arguments par défaut placés ailleurs ne seront pas utilisés.

24
David Brown

Les valeurs par défaut doivent toujours aller dans le fichier d'en-tête, si la fonction est déclarée dans un fichier d'en-tête.

C'est parce que le compilateur utilisera le fichier d'en-tête pour TOUTES les unités de compilation qui utilisent votre classe [à moins que vous ne soyez "méchant" et n'utilisez pas le fichier d'en-tête partout où il devrait aller].

Étant donné que le compilateur ajoute des arguments par défaut lorsqu'il compile le code qui APPELLE la fonction (dans ce cas, le constructeur), peu importe les valeurs par défaut dans le fichier .cpp.

Bien sûr, dans ce cas, il n'y a qu'un seul "utilisateur" du fichier d'en-tête, et un seul endroit où le constructeur est appelé. Mais avoir des valeurs par défaut dans le fichier .cpp est généralement faux [sauf s'il s'agit d'une fonction locale].

Vous obtenez des bogues très "intéressants" si vous "mélangez" les valeurs par défaut - par exemple si votre .cpp a une valeur par défaut et le fichier de tête une autre. Si vous êtes vraiment compétent, vous pouvez même demander au compilateur de générer des valeurs par défaut différentes pour différents appels à la fonction, ce qui entraînera presque certainement des accrochages si le code repose sur la valeur par défaut d'une valeur particulière. Et ne soyez pas tenté de copier les valeurs par défaut de l'en-tête dans le fichier .cpp "juste pour le rendre plus facile à voir". Si quelqu'un modifie jamais la valeur par défaut, alors il est presque certain que cela ne changera pas aux deux endroits, et peut-être pire: changer les mauvaises valeurs par défaut, afin qu'il ne fasse pas ce qui était prévu.

64
Mats Petersson

.h vs. .cpp est un hareng rouge. La règle est que les arguments par défaut peuvent être utilisés dans les déclarations de fonction et dans la définition de la fonction. Vous n'êtes pas autorisé à redéfinir un argument par défaut, pas même à la même valeur. Ce n'est donc pas légal:

void f(int, int = 3);
void f(int, int = 3); // error: redefinition of default argument

Cependant, les déclarations suivantes peuvent ajouter des arguments par défaut:

void f(int, int = 3);
void f(int = 4, int = 3);
f(); // calls f(4, 3);

De plus, à tout moment où la fonction est appelée, les arguments par défaut qui ont été vus à ce point peuvent être utilisés:

void f(int, int =3);
f(1); // calls f(1, 3);
void f(int = 4, int = 3);
f(1); // calls f(1, 3);
f();  // calls f(4, 3);

Dans l'exemple d'origine, le fichier .h définit un argument par défaut, et toute unité de traduction qui utilise cet en-tête peut utiliser cet argument par défaut:

Class c3(1, 2, 3);
Class c2(1, 2);

De plus, le fichier .cpp définit un argument par défaut supplémentaire, donc après cette déclaration, le constructeur peut être appelé avec un, deux ou trois arguments:

Class c3(1, 2, 3);
class c2(1, 2);
class c1(1);
8
Pete Becker

Il n'existe pas de paramètre par défaut pour la définition d'un fichier en C++ - il n'existe que dans la déclaration.

Ce qui se passe, c'est que le compilateur voit une fonction qui manque ces derniers paramètres. Si ceux-ci sont par défaut, il peut remplir les blancs pour construire le code objet pour appeler la fonction comme si l'appel de fonction avait ces paramètres.

PS: Item 38/Scott Myers/Effective C++ - Ne jamais redéfinir une valeur de paramètre par défaut héritée.

2
Ed Heal