2012-03-22 8 views
7

Oto pytanie, które pojawia się wielokrotnie w implementacji klasy C++. Ciekawi mnie, jakie są tutaj ludzkie myśli. Który kod preferujesz i dlaczego?C++ Funkcje prywatne: czy przekazywać zmienną składową klasy według parametru funkcji, czy nie

class A 
{ 
public: 
    /* Constructors, Destructors, Public interface functions, etc. */ 
    void publicCall(void); 

private: 
    void f(void); 

    CMyClass m_Member1; 
}; 

z

void A::publicCall(void) 
{ 
    f(); 
} 

void A::f(void) 
{ 
    // do some stuff populating m_Member1 
} 

Lub alternatywnie:

class A 
{ 
public: 
    /* Constructors, Destructors, Public interface functions, etc. */ 
    void publicCall(void); 

private: 
    void f(CMyClass &x); 

    CMyClass m_Member1; 
}; 

z

void A::publicCall(void) 
{ 
    f(m_Member1); 
} 

void A::f(CMyClass &x) 
{ 
    // do some stuff to populate x, 
    // locally masking the fact that it's really m_Member1 
} 

Chyba zawsze preferują drugą bo wtedy f może wtedy działać na dowolnym instancja CMyClass ale, powiedziałem, mam dużo kodu, gdzie pierwszy jest całkowicie ważny, ponieważ f będzie działał tylko na m_Member1 i naprawdę podzielę go na dwie funkcje, aby kod był bardziej czytelny.

Tak, to jest raczej pytanie do dyskusji niż pytanie "odpowiedź", ale jestem bardziej zainteresowany rozumowaniem. Zaznaczę jako odpowiedź odpowiedź, która daje dobre uzasadnienie lub dobre kryterium.

Pamiętaj też, że to tylko zabawny przykład. Klasa będzie większa niż ta w rzeczywistości, a zatem organizacja jest ważna.

+1

W twoim drugim przypadku możesz ustawić 'f' statyczny i stworzy on prawie identyczny kod do pierwszego przypadku. –

+1

@Kerrek SB, To prawda i jest świetnym punktem. W rzeczywistości nie ma powodu, dla którego 'f()' musi być nawet członkiem tej klasy. Może to być samodzielna funkcja użyteczności. Wystarczy powiedzieć na razie, że 'f()' nie jest szczególnie użyteczne, z wyjątkiem kontekstu tej klasy. –

+0

dlaczego pierwsze f nie może działać na żadnej instancji CMyClass? – aib

Odpowiedz

1

Zadaj sobie pytanie: czy teraz ma jakieś znaczenie lub może mieć jakiekolwiek znaczenie w przewidywalnej przyszłości, aby wywołać f() z obiektem innym niż m_Member1?

Jeśli odpowiedź brzmi:

  • nr. Czy parametrless f() jako m_Member1 jest nieodłączną częścią A.
  • Tak. Zrób f(CMyClass &). Nawet jeśli teraz używasz tylko m_Member1, nie jest to nieodłączną właściwością obsługiwanych klas.
  • Może. Cóż ... Powiedziałbym, idź z parametremless f(). Zawsze istnieje możliwość zmiany zdania (właściwie, jeśli rzeczywiście jest dość banalna).

Należy również pamiętać, że funkcja f() może wywołać inną funkcję g(CMyClass &), ale nie odwrotnie. Tak więc, w zależności od tego, co robi f(), może to ograniczyć opcje.

+0

+1 , ale zamierzam zakwestionować kilka części tego, co powiedziałeś w duchu zdrowej debaty (głównie dlatego, że chcę powodów): Jeśli odpowiedź na twoje pytanie brzmi "nie", to dlaczego wolisz 'f()'? Poza tym, dlaczego wolisz beznapięciowe 'f()' nad drugim? Sądzę, że twoje ostatnie dwa zdania dają tutaj pewne uzasadnienie ... –

+0

Po pierwsze, ponieważ 'm_Member1' jest uważany za unikalną część' A' (na przykład 'Head' jest częścią' Body'), to 'f()' może być interpretowane jako operacja na 'A', nawet jeśli musi dotknąć 'm_Member1' varaible (' Body :: pickYourNose() 'nie potrzebuje odniesienia do twojego' Głowy' lub twojego 'Nosa'). Po drugie: ponieważ jeśli napiszesz 'g (CMyClass &)', który musi zadzwonić 'f()' będziesz teraz, że myliłeś się! – rodrigo

+0

Ponadto, mając dwa odniesienia do tego samego obiektu w tym samym miejscu ('member1' i' m_Member1') bez przyczyny, prawdopodobnie nie jest to dobry pomysł. – rodrigo

3

Skoro pytasz o opinie, jeśli samodzielna funkcja f(CMyClass&) ma sens i jest możliwa do zastosowania, to również bym ją preferował. Wybrałbym pierwszy przypadek, jeśli operacja wykonana przez f ma sens tylko w kontekście klasy A, jeśli CMyClass ma sens tylko w kontekście A, lub zależy od innych atrybutów A. Myślę, że trzeba podjąć decyzję w zależności od problemu.

+0

"Wybrałbym drugi przypadek, gdyby operacja wykonana przez f miała sens jedynie w kontekście klasy A." Czy chciałeś powiedzieć "pierwszy przypadek"? –

+0

@ChrisA Tak, rzeczywiście, miałem na myśli pierwszy przypadek! Naprawię to. – juanchopanza

1

Czy w drugim przykładzie nie jest f lepiej jako funkcja statyczna z A lub funkcją globalną lub, być może, funkcją składową CMyClass?

Oczywiście są przypadki, w których lepiej wysłać argument za każdym razem, gdy wywołasz tę funkcję, ale dlaczego miałbyś wysłać ją ponownie, gdy już masz obiekt CMyClass w obiekcie A. Jeśli potrzebujesz obu obiektów CMyClass do interakcji, lepiej może być dodanie ich do listy funkcji członkowskich CMyClass, a nie do A.

Również, jak stwierdza Clean Code, lepiej funkcjonują funkcje bez żadnych argumentów, niż te z argumentami. Gdy inny programista próbuje odczytać funkcję, musi rozszyfrować/zwrócić uwagę na drugi parametr, oprócz nazwy funkcji.

+0

+1 Niezłe punkty. –

1

Oparłbym odpowiedź na kontekście. Jeśli obecnie lub może pewnego dnia wystąpić wiele instancji zmiennych członkowskich, na których może działać f, to z pewnością przekazujemy je/them jako parametry. Jednakże jeśli f działa na określonych elementach stanu instancji A, nic bym mu nie przekazał. Istnieje wiele przypadków, w których zawsze będzie tylko jeden foo w A. W tym momencie staje się niemądry, aby uczynić foo parametrem f. I nieco mniej wydajne, chyba że f jest inline, ponieważ nie tylko jest przekazywany ten wskaźnik, ale także adres foo, który jest dodatkową kopią na stosie.

2

Jak zwykle to zależy. Każdy scenariusz jest inny.

W konkretnym przykładzie, który podałeś - najpierw wykluczyłbym Twoją alternatywę (void A::f(CMyClass &x)) głównie dlatego, że "pachnie" źle (jak to ujął Martin Fowler). Jest to funkcja prywatna i jeśli nie musisz jej teraz używać, dla innych instancji, użyj jej. Zawsze możesz go zmienić, jeśli zajdzie taka potrzeba.

Wyobraź sobie, co by się stało, gdyby f miał 2 parametry. 3 parametry. 10. Czy miałoby sens, aby wysłać je za każdym razem? Czy nie byłoby lepiej mieć tych parametrów członków?

A co jeśli f musiał wysłać niektóre z tych argumentów do innych metod A? Czy nie ma większego sensu używać członków do tego?

Wszystko to zakłada, że ​​f potrzebuje innych informacji, które posiada A, w przeciwnym razie zostałabym przeniesiona na metodę CMyClass.

+0

+1, podoba mi się tutaj rozumowanie. Ta warta 2,3,10 cecha jest szczególnie ważna dla mojej klasy, ponieważ zwiększa się. –

Powiązane problemy