2013-02-15 12 views
15

del compilatore:g ++ 4.7.2parametri di default nei file .he cpp

OK. Quindi sono confuso sui parametri di default nei file .h e .cpp. È menzionato in molti posti (incluso questo sito) che i parametri predefiniti possono essere aggiunti solo in file .h e non in file .cpp. Tuttavia, questo codice si rivela sbagliato:

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; 
} 

Ora, secondo quello che ho provato, i parametri di default possono essere aggiunto ai file .cpp. Tuttavia, le seguenti restrizioni tengono:

  1. I parametri di default presenti in .cpp e .h file non deve sovrapposizione. Ad esempio Class(a, b, c=1) (nel file .h) e Class::Class(a,b,c=2) (nel file .cpp) non è valido.

    È una regola ben nota che una volta aggiunti i parametri di default a , tutte le variabili dichiarate dopo devono contenere anche i valori di default . Chiamiamo questa la regola defpara. Ora,

  2. Le variabili indicate nella dichiarazione di funzione (.h file) devono obbedire al defpara regola vale a dire Class(a, b=2, c) (nel file h) è valida indipendentemente da ciò che è dichiarato nel file cpp.

  3. Se si considerano le variabili aventi valori di default (come un intersezione dei valori standard di .h e .cpp file), sarebbe seguire il defpara regola. Ad esempio, Class(a, b, c=1) (nel file .h) e Class::Class(a,b=2,c) (nel file .cpp) è valido. Ma Class(a, b, c=1) (nel file .h) e Class::Class(a=2,b,c) (nel file .cpp) è non valido.

Quindi .... ho ragione, ho sbagliato ???

risposta

14

Questo funziona solo perché la tua funzione principale è anche nel tuo file test.cpp, quindi vede l'argomento predefinito specificato nell'implementazione della classe. Se inserisci la tua funzione main in un file separato che include solo test.h, questo codice non verrà compilato.

Un altro modo di guardarlo è, quando un altro include test.h, tutto ciò che il codice vede è quanto dichiarato in test.h, quindi gli argomenti di default messi altrove non verranno utilizzati.

32

I valori di default devono sempre andare nel file di intestazione, se la funzione è dichiarata in un file di intestazione.

Questo perché il compilatore utilizzerà il file di intestazione per TUTTE le unità di compilazione che usano la tua classe [a meno che tu non sia "cattivo" e non usi il file di intestazione ovunque debba andare].

Poiché il compilatore aggiunge gli argomenti predefiniti quando compila il codice che CHIAMA la funzione (in questo caso il costruttore), non avrà importanza quali sono i valori predefiniti nel file .cpp.

Naturalmente, in questo caso, esiste un solo "utente" del file di intestazione e solo un punto in cui viene chiamato il costruttore. Ma avere i valori predefiniti nel file .cpp è generalmente sbagliato [a meno che non si tratti di una funzione locale].

Si ottengono bug molto "interessanti" se si "mescolano" i valori di default - ad es. se il tuo .cpp ha un default, e il headefile ne ha uno diverso. Se sei veramente abile, puoi anche ottenere che il compilatore generi diverse impostazioni predefinite per le diverse chiamate alla funzione, il che quasi certamente porterà ad un certo headscratching se il codice si basa sul valore predefinito di un determinato valore. E non essere tentato di copiare i valori predefiniti dall'intestazione al file .cpp "solo per renderlo più facile da vedere". Se qualcuno cambia l'impostazione predefinita, è quasi certo che non cambierà in entrambi i casi, e forse peggiore: cambierà i valori predefiniti sbagliati, quindi non farà ciò che è stato previsto.

+0

significa in definizione di metodo in file cpp, non è necessario scrivere il valore predefinito? – laike9m

+1

Sì, non dovresti averlo due volte e il file di intestazione è dove appartiene. –

2

Non esiste un parametro predefinito per la definizione di un file in C++, esiste solo nella dichiarazione.

Quello che succede è che il compilatore vede una funzione che non ha gli ultimi parametri. Se quelli sono predefiniti, è possibile riempire gli spazi vuoti per costruire il codice oggetto per chiamare la funzione come se la chiamata alla funzione avesse quei parametri.

PS: Articolo 38/Scott Myers/Effective C++ - Non ridefinire mai un valore di parametro predefinito ereditato.

+0

Minore: nella 3a edizione è l'articolo 37 (che vale sicuramente una lettura) – nmarler

5

.h vs. .cpp è un'aringa rossa. La regola è che gli argomenti predefiniti possono essere utilizzati nelle dichiarazioni di funzioni e nella definizione della funzione. Non è consentito ridefinire un argomento predefinito, nemmeno con lo stesso valore. Quindi questo non è legale:

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

Tuttavia, le dichiarazioni successive possono aggiungere gli argomenti di default:

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

Inoltre, in qualsiasi punto in cui la funzione viene chiamata, gli argomenti di default che sono stati visti in quel punto può essere utilizzato:

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); 

nell'esempio originale, il file .h definisce un argomento predefinito e ogni unità di traduzione che utilizza tale intestazione può utilizzare tale argomento predefinito:

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

Inoltre, il file cpp definisce un argomento di default aggiuntivo, così dopo questa dichiarazione il costruttore può essere chiamato con uno, due, o tre argomenti:

Class c3(1, 2, 3); 
class c2(1, 2); 
class c1(1); 
Problemi correlati