2015-12-11 13 views
9

Zastanawiałem się, czy mogę ominąć stosując pobierające gdybym tylko dozwolone zmienną referencyjną const, co następujeCzy mogę używać odwołań do const zamiast funkcji getter?

#include <string> 

class cTest 
{ 
    private: 
     int m_i; 
     std::string m_str; 

    public: 
     const int & i; 
     const std::string & str; 

    cTest(void) 
    : i(m_i) 
    , str(m_str) 
    {} 
}; 

int main(int argc, char *argv[]) 
{ 
    cTest o; 
    int i = o.i; // works 
    o.i += 5; // fails 
    o.str.clear(); // fails 

    return 0; 
} 

Zastanawiam się, dlaczego ludzie nie wydają się to zrobić w ogóle. Czy brakuje mi jakiejś poważnej wady? Proszę wnieść wkład do listy zalet i wad, i poprawić je, jeśli to konieczne.

Zalety:

  1. Nie ma nad głową przez wywołań funkcji getter.
  2. Program zmniejsza rozmiar, ponieważ jest mniej funkcji.
  3. Ciągle mogę modyfikować wewnętrzne klasy, zmienne referencyjne zapewniają warstwę abstrakcji.

Wady:

  1. Zamiast funkcji getter, mam kilka odniesień. Zwiększa to rozmiar obiektu.
  2. Użytkownicy mogą zepsuć prywatnych członków, ale ci ludzie są złośliwi, prawda?

Odpowiedz

7

Niektóre poważne wady rzeczywiście (oprócz 2 wadę, że również wspomnieć, którą również umieścić w kategorii „ciężkim”):

1) Musisz dostarczyć (i dlatego utrzymują) copy constructor: domyślna kompilacja nie działa.

2) Musisz podać operatora przypisania: domyślny kompilator nie będzie działać.

3) Zastanów się dobrze nad implementacją semantyki ruchu. Znowu domyślna kompilacja nie będzie działać.

Te trzy rzeczy oznaczają referencyjny wzorzec antynarkotykowy, który proponuje się nieużywać. Nie rób tego!

+5

Nie wspominając, że nadszedł dzień, w którym chcesz użyć bardziej wydajnej reprezentacji danych, a nie możesz, ponieważ potrzebujesz prawidłowego odniesienia do tych typów. – chris

+0

@chris: To jest dobra uwaga. Nawet jeśli masz funkcję zwracającą const ref, zawsze możesz ją zmienić, aby zwrócić kopię wartości w przypadku zmiany modelu danych. – Bathsheba

2

Jedną z zalet funkcji getter jest to, że możesz w pewnym momencie - chcieć zmienić zwracaną wartość - i bez funkcji getter nie możesz tego zrobić. To scenerio wymagałoby, abyś faktycznie zwrócił referencję, co jest mniej powszechne w C++. [edit] ale z semantyką ruchu zamiast odwołań, to powinno być wykonalne [/ edit]

Możesz także umieścić breakpoint w funkcji getter, aby dowiedzieć się, kto odczytuje jego wartość, możesz dodać rejestrowanie itp. Nazywa się to enkapsulacją .

Inną zaletą gettera jest to, że w kompilacjach debugowania można dodać dodatkowe kontrole/potwierdzenia dotyczące zwracanych danych.

W kompilatorze końcowym zostaną wbudowane funkcje gettera, co spowoduje powstanie kodu podobnego do proponowanego.

niektóre Dodatkową wadą:

1) kod szablonu będzie chciał uzyskać wartości za pomocą wywołania funkcji, tj. size(), jeśli zmienisz ją na zmienną &, to nie będziesz mógł jej użyć w niektórych szablonach. Jest to problem spójności.

0

Jeśli chcesz uniknąć metod pobierających i ustawiających, użycie referencyjnego elementu const nie jest rozwiązaniem.

Zamiast tego będziesz chciał zapewnić poprawność stałych na otaczającej strukturze (która automagicznie zapewnia stały dostęp do członków) i po prostu pozwól członkom być tym, czym logicznie potrzebują.

Pamiętaj, aby przeczytać, kiedy pobierający i ustawiający mogą, powinni lub mogą być przełączani z publicznymi członkami danych. Zobacz np. this question. Zauważ, że jeśli zmienisz interfejs, zwiastunem setter/getters jest to, że wywołanie gettera nie wpłynie na strony wywołania. Rzeczywistość wydaje się twierdzić inaczej, i np. refaktoryzacja członka wraz ze wszystkimi jego punktami dostępowymi jest trywialną operacją dla każdego szanującego się edytora kodu C++.

Chociaż można argumentować za hermetyzacją, wolałbym raczej argumentować za poprawnością const, co zmniejsza potrzebę dużej enkapsulacji i naprawdę upraszcza kod całkiem sporo.

Powiązane problemy