2009-07-29 2 views
14

Próbuję utworzyć klasę za pomocą dwóch metod o tej samej nazwie, używanych w celu uzyskania dostępu do prywatnego członka. Jedna metoda jest publiczna i jest zakwalifikowana, druga jest prywatna i nie jest const (używana przez klasę znajomego w celu modyfikacji członka poprzez odwołanie do referencji).prywatna niestanowiąca i publiczna funkcja członka wspólnoty - współistniejąca w pokoju?

Niestety, otrzymuję błędy kompilacji (używając g ++ 4.3): Kiedy używam obiektu nie const do wywoływania metody, g ++ narzeka, że ​​niestanowiskowa wersja mojej metody jest prywatna, nawet jeśli publiczna (const) wersja istnieje.

Wydaje się to dziwne, ponieważ jeśli nie istnieje wersja prywatna, która nie istnieje, wszystko kompiluje się dobrze.

Czy istnieje sposób, aby to zadziałało? Czy jest kompilowany na innych kompilatorach?

Dzięki.

Przykład:

class A 
{ 
public: 
    A(int a = 0) : a_(a) {} 
public: 
    int a() const { return a_; } 
private: 
    int & a()  { return a_; } /* Comment this out, everything works fine */ 
    friend class B; 
private: 
    int a_; 
}; 


int main() 
{ 
    A  a1; 
    A const a2; 

    cout << a1.a() << endl; /* not fine: tries to use the non-const (private) version of a() and fails */ 
    cout << a2.a() << endl; /* fine: uses the const version of a() */ 
} 
+0

Dlaczego to nie? C++ umożliwia konwersję z const const na vis parametr vis. – jkeys

Odpowiedz

13

rozdzielczości dzieje przed przeciążeniem kontroli dostępu, więc jeśli nazywają to metoda na const A, non-const członek został wybrany jako lepszego dopasowania. Kompilator następnie nie powiedzie się z powodu kontroli dostępu.

Nie ma sposobu, aby "wykonać tę pracę", moim zaleceniem byłoby zmienić nazwę funkcji prywatnej. Czy istnieje potrzeba posiadania prywatnego akcesora?

+0

Ukryta klasa byłaby moim najlepszym wyborem - jak używanie struktury węzła wewnątrz większej klasy. – jkeys

+0

To zbyt źle. Podejrzewałem, że tak jest, ale nie rozumiem, dlaczego tak musi być. Mam nadzieję, że ktoś pokaże mi, dlaczego musi być, więc mogę spokojnie odpocząć. Powodem, dla którego chcę tego zachowania, jest to, że zazwyczaj piszę moje moduły pobierające i ustawiające jako dwie const/non const wersja tej samej metody, bez prefiksu "get"/"set". W przypadku tej konkretnej klasy nie chcę dopuszczać żadnej klasy z wyjątkiem jednej do użycia seterów (stąd deklaracja klasy przyjaciela). – mmocny

+0

Zdolność do przeciążania funkcji jest przede wszystkim przydatna, gdy funkcje wykonują tę samą lub podobną operację logiczną, ale na innym typie argumentu (szczególnie przydatne przy pisaniu kodu generycznego w szablonach). Pobieranie wartości czegoś jest inną operacją niż uzyskanie odniesienia do czegoś w celu jego aktualizacji. Z tego powodu ma sens (przynajmniej dla mnie!), Aby nadać funkcjom różne nazwy. Myślę, że "pływasz pod prąd", jeśli próbujesz zachować te same nazwy. –

2

Wybierze tylko wersję const, jeśli obiekt jest zadeklarowany jako const, w przeciwnym razie wybierze wersję inną niż const (nawet jeśli spowoduje to błąd).

To powinno działać:

cout << ((const A*)&a1)->a() << endl; 

lub to:

A const& ra1 = a1; 
cout << ra1.a() << endl; 
+1

Myślę, że wolałbym 'const_cast (a1) .a()'. Wydawałoby się to nieco bezpieczniejsze. –

+0

Tak, to jest najlepsze sposób to zrobić, jeśli masz zamiar użyć rzutowania.Nie sądzę, że jest bezpieczniejsze niż druga metoda, jednak kompilator wymusi pełne bezpieczeństwo typu dla przypisania do odniesienia.wszyscy, myślałem, że zaimplementujesz to, na przykład, zmieniając sygnatury metod z "A" i "A const", gdy przekazujesz te rzeczy, zamiast bezpośrednio nimi manipulować, jak w tym oczywiście wymyślonym przykładzie. –

+1

Nie rozumiem, dlaczego odpowiedź Charlesa Baileya ma tak wysokie głosowanie niż ta (odpowiednia i działająca IMHO) odpowiedź Tima Sylvestera, która pokazuje przeciwieństwo "Nie ma sposobu" na wykonanie tej pracy "_ Właściwie to przybyłem tutaj, ponieważ wiedziałem, że tak jest Problem tkwił gdzieś w moim kodzie, ale zapomniałem gdzie i jak. (Btw. Rozwiązałem go dokładnie tak, jak opisano powyżej. Może być, powinienem spróbować google na moim własnym lokalnym kodzie źródłowym następnym razem ...) – Scheff