2013-01-09 16 views
6

Eventuali duplicati:
Difference between const declarations in C++const nella dichiarazione della funzione

#include <iostream> 

class Bar{}; 

void foo(const Bar x){} //l5 
void foo(Bar x){}  //l6 
void foo(Bar const x){} //l7 

////pointer functions 

void foo(const Bar* x){} //l11 
void foo(Bar* x){}  //l12 
void foo(Bar* const x){} //l13 

uscita del compilatore: (per farla breve l5, l6, l7 conflitto, ma solo l12, l13 conflitto)

untitled.cpp:6:6: error: redefinition of ‘void foo(Bar)’ 
untitled.cpp:5:6: error: ‘void foo(Bar)’ previously defined here 
untitled.cpp:7:6: error: redefinition of ‘void foo(Bar)’ 
untitled.cpp:5:6: error: ‘void foo(Bar)’ previously defined here 
untitled.cpp:13:6: error: redefinition of ‘void foo(Bar*)’ 
untitled.cpp:12:6: error: ‘void foo(Bar*)’ previously defined here 

Cosa succede?

  1. Qual è il significato di ciascuna delle dichiarazioni
  2. Perché tutte 3 le dichiarazioni in conflitto con le funzioni degli oggetti, ma solo 2 con funzioni di puntatore?
  3. Si prega di elaborare che il conflitto è tra il l12 e l13, anche se l12 non contiene const parola chiave
  4. Veramente dispiaciuto se domanda banale

risposta

5

Il "problema" è che const ness del valore di un parametro non partecipa all'overloading!

In primo luogo, Bar const e const Bar sono già il significato identico, quindi avrebbero automaticamente un problema. Ma come parametro di funzione lo const non si applica al sovraccarico, quindi anche la versione della funzione Bar ha lo stesso aspetto. Lo const nel paremeter dice al compilatore che non si intende modificarlo nel corpo della funzione.

Per lo stesso motivo, Bar* e Bar* const sono trattati allo stesso: il const vale per il valore del parametro (non quello che indicò) e non partecipa in sovraccarico, in modo da aver definito la stessa funzione.

D'altra parte const Bar* significa qualcosa di totalmente diverso: un puntatore non-const a un oggetto const (di tipo Bar). Poiché il tipo è diverso, partecipa all'overloading e consente a tale funzione di essere unica.

1

Non importa se si mette const prima o dopo il nome del tipo .

15 e 17 hanno lo stesso elenco di argomenti.
Queste 2 funzioni sono considerate avere lo stesso prototipo e sono duplicati.

Funzione # 1

void foo(const int x) { 
return; 
} 

Funzione # 2 - Duplicate lista degli argomenti di parametri

void foo(int const x) { 
return; 
} 

La posizione del const è la stessa di 15 e 17 nell'esempio che avete.

O funziona secondo Wikipedia:

http://en.wikipedia.org/wiki/Const-correctness

+0

Re la tua prima frase: non ha importanza per il compilatore, in questo particolare contesto. In generale, tuttavia, 'const' modifica ciò che lo precede, e mettendo sistematicamente' const' dopo ciò che modifica (ad esempio 'const const', e non' const int') rende il codice più leggibile. –

0

La ragione i primi tre creare un conflitto, è che il compilatore non può capire che funzionano da utilizzare in ogni caso. Quando chiami il foo(BarObject);, il compilatore potrebbe utilizzare molto bene qualsiasi di essi, sia che sia stato dichiarato BarObject come const oppure no.

Tuttavia su quelli con parametri come puntatori, quando si chiama foo(BarPointer); se BarPointer era dichiarato const Bar* BarPointer; il compilatore di accompagnamento ]11, perché assicura l'oggetto puntato non viene modificato nella funzione (non è il caso quando si passa da valore come nei primi tre). Se non è , non sa se dovrebbe chiamare ]12 o ]13 perché quello che significa "Bar* const x", "x non può indicare nient'altro che quello che è stato passato come parametro" e questo non riguarda il chiamante .

Piccolo riferimento alle dichiarazioni:

const Bar x // x is an immutable copy of the original parameter. 
Bar const x // same as above and gets compiled, but cdecl says it is a syntax error. 

const Bar* x // x points to an object that can't be changed. 
Bar* const x // x can't point to any other object than the parameter passed. 
0

Fondamentalmente, perché C++ copia i valori quando si chiama una funzione, non c'è nulla per distinguere i primi tre da una prospettiva chiamanti. (Il chiamante sa che la funzione non può cambiare il proprio valore che sta passando, quindi ogni parametro di funzione è implicitamente costante in molti aspetti, dal punto di vista del chiamante in ogni caso).

Quando si parla di puntatori tuttavia, se si passa un puntatore a una costante rispetto a un puntatore a una non costante, c'è una differenza per il chiamante (uno non cambierà i propri contenuti, l'altro potrebbe). Questo è il motivo per cui l11 e l12 non sono in conflitto.

l12 e 13 conflitto però perché sono entrambi puntatori a Bar * (uno è un puntatore const, uno non è, quindi lo stesso problema di l5-l7, non c'è differenza per il chiamante).

Quest'ultimo punto può essere un po 'complicato - notare che mentre int const *a è lo stesso const int *a, questi non sono uguale int * const a, i primi due sono puntatori a una costante int, l'altro è un puntatore costante un int (cioè il valore del puntatore non può cambiare in seguito).

0
void foo(const Bar x){} 
void foo(Bar const x){} 

Quanto sopra due sono identici perché entrambi dicono x è di tipo Bar ed è const.

void foo(Bar x){} 

Questo uno in conflitto con quanto sopra 2, perché se è xconst o non è un dettaglio di implementazione della funzione, e viene scartato dal compilatore dalla firma della funzione. Quindi tutte e 3 le funzioni finiscono per avere la stessa firma che è void foo(Bar x).

void foo(Bar* x){} 
void foo(Bar* const x){} 

Questo è simile al caso precedente; stai indicando che il puntatore x è const, ad esempio non ti ricolleghi a x a qualcosa di diverso all'interno della tua funzione. In entrambi i casi l'oggetto Bar a cui punta x non è const. Pertanto, lo const di x è un dettaglio di implementazione della funzione.

void foo(const Bar* x){} 

Qui sei indicando che x punti a un oggetto che è Barconst. Questo è diverso dai precedenti 2 casi, quindi non c'è conflitto.

0

Per le prime tre funzioni - const non è rilevante per la risoluzione di sovraccarico in caso di variabile trasferita dal valore . Copia dell'argomento creato nello stack e non ha senso se questa copia è cambiata o meno dal punto di vista esterno (chiamante). Importa per la funzione stessa (dentro).

Per il secondo caso, le funzioni basate su puntatore, è una parte importante della risoluzione dell'overload delle funzioni, poiché le copie non vengono create nello stack e dal punto di vista esterno (chiamante) significa che la funzione modificherà il valore dell'argomento.

Per ultime due funzioni usano dire a un compilatore: c'è x puntatore a Bar, e questo valore Bar puntato da x posso cambiare. Ma nel primo caso è possibile modificare il valore del puntatore x stesso (ad esempio, puntare a un altro Bar) opposto al secondo caso. Ed eccoci nella prima situazione: copie di puntatori sono in pila e non ha senso per la risoluzione di sovraccarico se cambiano all'interno della funzione o meno.

Problemi correlati