2013-01-09 19 views
6

Powiel możliwe:
Difference between const declarations in C++const pozycji słów kluczowych w deklaracji funkcji

#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 

wyjście Compiler (długie opowiadanie l5, l6, l7 konfliktu, lecz tylko l12, l13 konfliktu)

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 

Co się dzieje?

  1. Jakie jest znaczenie każdego z deklaracji
  2. Dlaczego wszystkie 3 deklaracje konflikt z funkcji obiektu, ale tylko 2 z funkcjami wskaźnika?
  3. Należy opracować że konflikt jest między l12 i l13, choć l12 nie zawiera const słowa kluczowego
  4. Naprawdę przepraszam jeśli trywialne pytanie

Odpowiedz

5

"Problem" polega na tym, że wartość parametru nie bierze udziału w przeciążeniu!

Po pierwsze, Bar const i const Bar mają już identyczne znaczenie, więc automatycznie pojawiłyby się problemy. Ale jako parametr funkcji const nie ma zastosowania do przeciążania, więc wersja tej funkcji również wygląda tak samo. Wartość const w paremeterze informuje kompilator, że nie zamierza się go modyfikować w treści funkcji.

Z tego samego powodu, Bar* i Bar* const traktuje taki sam: const odnosi się do wartości parametru (nie to, co wskazywał) oraz nie uczestniczy w przeciążenia, więc pan zdefiniował tę samą funkcję.

Z drugiej strony const Bar* oznacza coś zupełnie innego: niestały wskaźnik do obiektu const (typu Bar). Ponieważ typ jest inny, bierze udział w przeciążeniu i pozwala na unikalność tej funkcji.

1

To nie ma znaczenia, czy można umieścić const przed lub po nazwie typu .

15 i 17 mają tę samą listę argumentów parametrów.
Te dwie funkcje mają ten sam prototyp i są duplikatami.

Funkcja # 1

void foo(const int x) { 
return; 
} 

Funkcja # 2 - Duplikat lista argumentów parametr

void foo(int const x) { 
return; 
} 

Stanowisko const jest taka sama jak 15 i 17 w tym przykładzie masz.

Albo będzie pracować według Wikipedii:

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

+0

Powtórz zdanie: nie ma to znaczenia dla kompilatora, w tym konkretnym kontekście. Zasadniczo jednak "const" modyfikuje to, co je poprzedza, a umieszczanie "const" systematycznie po tym, co modyfikuje (tj. 'Int const', a nie' const int') sprawia, że ​​kod jest bardziej czytelny. –

0

Powodem trzy pierwsze stworzyć konflikt, jest to, że kompilator nie może dowiedzieć się, która funkcjonowała do wykorzystania w każdym przypadku. Podczas wywoływania foo(BarObject); kompilator może bardzo dobrze użyć dowolnego z nich, niezależnie od tego, czy został zadeklarowany jako const, czy też nie.

jednak na tych, o parametrach jak wskaźniki, gdy dzwonisz foo(BarPointer); jeśli BarPointer został uznany jako const Bar* BarPointer; kompilator wzrośnie ]11, ponieważ zapewnia ona przedmiotem wskazał nie zostaną zmienione w funkcji (nie w przypadku, gdy przechodząc przez wartość jak w pierwszych trzech). Jeśli nie jest to const, to nie wie, czy powinien zadzwonić pod numer ]12 lub ]13, ponieważ oznacza to, że Bar* const x oznacza, że ​​"nie może wskazywać nic poza tym, co zostało przekazane jako parametr", a to nie dotyczy dzwoniącego .

Mały numery zgłoszeń:

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

Zasadniczo, ponieważ C++ kopiuje wartości podczas wywoływania funkcji, nie ma nic, aby odróżnić trzy pierwsze z punktu widzenia rozmówców. (Dzwoniący wie, że funkcja nie może zmienić swojej własnej wartości, więc każdy parametr funkcji jest nieodmiennie stały pod wieloma względami, z punktu widzenia osoby dzwoniącej w każdym przypadku).

Kiedy jednak mówimy o wskaźnikach, jeśli przekazujemy wskaźnik do stałej, a wskaźnik do nie stałej, występuje różnica między dzwoniącymi (jeden nie zmienia waszych rzeczy, a drugi może). Właśnie dlatego l11 i l12 nie powodują konfliktów.

konflikt l12 i l13, ponieważ oba są wskaźnikami do paska * (jeden jest wskaźnikiem const, jeden nie jest, więc ten sam problem co l5-l7, nie ma różnicy dla dzwoniącego).

Ten ostatni punkt może być trochę trudne - pamiętać, że podczas int const *a jest taka sama jak const int *a te nie są taka sama jak int * const a, pierwsze dwa są wskaźnikami do stałej int, drugi jest stałym wskaźnikiem do int (tj. wartość wskaźnika nie może się zmienić w późniejszym czasie).

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

Powyższe dwa są identyczne, ponieważ oba powiedzieć x jest Bar typu i jest const.

void foo(Bar x){} 

ten jeden konflikty z powyżej 2 bo czy x jest const lub nie jest szczegółowo realizacja swojej funkcji i jest odrzucana przez kompilator z podpisem funkcji. Wszystkie 3 funkcje kończą się tym samym podpisem, który jest void foo(Bar x).

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

Jest to podobne do poprzedniego przypadku; wskazujesz, że wskaźnik x jest const, tzn. nie zmienisz punktu x na coś innego w ramach swojej funkcji. W obu przypadkach obiekt Bar, który wskazuje na x, jest inny niż const. Tak więc, const zjest szczegółem implementacji funkcji.

void foo(const Bar* x){} 

Tutaj jesteś wskazując, że x wskazuje na Bar obiektu, który jest const. Różni się to od poprzednich 2 przypadków, więc nie ma konfliktu.

0

Dla pierwszych trzech funkcji - const nie ma znaczenia na przeciążenie rozdzielczości w przypadku zmiennej przekazanej przez wartość. Kopia argumentu utworzonego na stosie i nie ma sensu, jeśli ta kopia uległa zmianie z zewnątrz (wywołującego) punktu widzenia. Ma znaczenie dla samej funkcji (wewnątrz).

Dla drugiego przypadku, funkcje oparte na wskaźnikach, to ważna część funkcji przeciążenia, ponieważ kopie nie są tworzone na stosie iz zewnątrz (wywołujący) punkt widzenia oznacza to, że funkcja będzie modyfikować wartość argumentu.

Na ostatnich dwóch funkcji używać powiedzieć kompilatora: jest x wskaźnik Bar, a to Bar wartość wskazanych przez x może zmienić. Ale w pierwszym przypadku możesz zmienić wartość wskaźnika x (powiedzmy, wskaż inny Bar) naprzeciwko drugiego przypadku. I oto jesteśmy w pierwszej sytuacji - kopie samych wskaźników są na stosie i nie ma sensu dla przeciążania rozdzielczości, jeśli zmienili się wewnątrz funkcji, czy nie.

Powiązane problemy