2013-05-29 10 views
12

Mam wątpliwości dotyczące metod prywatnych & funkcji. Powiedzmy, że mam pewne metody użytkowe, które nie muszą znajdować się w klasie. Ale te same metody muszą wywoływać inne, których nie chcę ujawniać użytkownikowi. Na przykład:Prywatny obszar nazw w plikach źródłowych

Suspect.h

namespace Suspect { 
    /** 
    * \brief This should do this and that and more funny things. 
    */ 
    void VerbalKint(void); // This is for you to use 
} 

Suspect.cpp

namespace Suspect { 
    namespace Surprise { 
    /** 
    * \brief The user doesn't need to be aware of this, as long 
    *  the public available VerbalKint does what it should do. 
    */ 
    void KeyserSoze(void) { 
     // Whatever 
    } 
    } // end Surprise 

    void VerbalKint(void) { 
    Surprise::KeyserSoze(); 
    } 
} 

Tak, ten układ działa. Po dodaniu Suspect.h widoczny jest tylko VerbalKint. ten można także osiągnąć stosując klasę i znakowanie VerbalKint jako statyczne:

class Suspect { 
public: 
    // Whatever 
    static void VerbalKint(void); 
private: 
    static void KeyserSoze(void); 
}; 

Chciałbym wiedzieć, czy jest jakaś różnica między tymi dwoma podejściami. Czy jest lepszy (szybszy, łatwiejszy do utrzymania) niż drugi?

Jakie są Twoje myśli?

+1

Powinieneś zrobić 'KeyserSoze'' static' również w klasie, jeśli chcesz, aby przykłady były równoważne. Jeśli jednak umieścisz go jako klasę w pliku nagłówkowym, to wszyscy, włącznie z tym plikiem nagłówkowym, mogą stwierdzić, że istnieje funkcja o nazwie 'KeyserSoze', więc nie można jej" ukryć ". –

+2

Po pierwsze: nie można utworzyć deklaracji przekazania statycznej funkcji bez uwzględnienia definicji klasy. – selalerer

+0

@JoachimPileborg, dzięki. Tęsknie za tym! –

Odpowiedz

5

Jeśli funkcje są „wolne”, należy użyć nazw anonimowy w *.cpp:

namespace Suspect { 
namespace Surprise { 
namespace { 
    void KeyserSoze(void) { 
     // Whatever 
    } 
} // end anon 
} // end Surprise 
} // end Suspect 

lub nawet:

namespace { 
    void KeyserSoze(void) { 
     // Whatever 
    } 
} // end anon 

ta utrzymuje ją z dala od klientów, więc nie mają dostępu, zależą od eksportów lub kolidują z nimi podczas łączenia. Zachowuje także niepotrzebne deklaracje, skracając czasy kompilacji i potencjalnie czasy łączeń lub rozmiary binarne, jeśli definicje są widoczne. Ostatecznie czyni to prywatnym, więc nie mogą na nim polegać i nie trzeba go utrzymywać do użytku. Nadal możesz je przekazać światu zewnętrznemu, jeśli wybierzesz (wskaźnik funkcji w przypadku KeyserSoze()).

W innych przypadkach lepiej jest zadeklarować prywatną funkcję członka w swojej klasie, a następnie zdefiniować ją w *.cpp (jeśli to możliwe). Zwykle wybierasz takie podejście, gdy potrzebujesz bliższych relacji z klasą (np. Kiedy potrzebujesz dostępu do niektórych członków). Powiedziałeś, że tak nie jest w tym pytaniu, ale powtarzam tylko, kiedy powinniśmy używać prywatnych członków.

+1

To jest najbardziej kompletna odpowiedź i obejmuje niektóre tematy, które miałem na myśli, więc przyjęta! –

9

Najlepszym rozwiązaniem jest zdefiniowanie wszystkich funkcji pomocniczych w nienazwanym obszarze nazw w Suspect.cpp, zamiast w przestrzeni nazw Suspect::Surprise.

W Twoim przypadku będzie to:

namespace{ 
void KeyserSoze(){ ... }; 
} 

Możesz po prostu zadzwonić KeyserSoze bez żadnych specyfikatorów przestrzeni nazw od wewnątrz Suspect.cpp.

można znaleźć więcej informacji na ten temat tutaj: Unnamed/anonymous namespaces vs. static functions

Inną alternatywą jest zadeklarować KeyserSoze być static, ale nie jest to zalecane przez normy. C++ standard czyta w punkcie 7.3.1.1 bez nazw nazw ustęp 2:

Użycie hasła statycznego jest przestarzała podczas deklarowania obiektów w zakresie przestrzeni nazw, bezimienny-namespace zapewnia doskonałą alternatywą

+1

'static' zostało niezmienione w C++ 11. – avakar

5

W rzeczywistości, nawet jeśli funkcja nie jest widoczna dla oka, gdy nie deklarujesz jej w żadnym nagłówku; nadal jest dostępny dla użytkownika, jeśli napisze oświadczenie.

W C++, mechanizm ukryć symbole deklarowanych na poziomie plików jest:

  • static na (globalne) zmiennych i funkcji
  • namespace { ... } (anonimowe obszary nazw) na cokolwiek chcesz (bardziej ogólnie, bardziej gadatliwy)

Na przykład:

// Suspect.cpp 

namespace Suspect { 

    static void KeyserSore() {} 

    void VerbalKing() { KeyserSore(); } 

} 
2

Główna różnica między umieszczaniem czegoś w klasie lub obszarze nazw jest taka, że ​​nie można dodać dodatkowych funkcji statycznych do klasy w innym pliku nagłówkowym.

to: A.H

namespace Fred { 
    void Somefunc(); 
} 

B.H.

namespace Fred { 
    void Anotherfunc(); 
} 

praca, choć ani nie b wiedzieć co siebie uczynił ich nazw. Może to powodować problemy niewykluczone, takie jak ten:

ch

namespace Fred { 
    void Thirdfunc(); 
} 

dh

namespace Fred { 
    bool Thirdfunc(); 
} 

którym jest wszystko cacy, aż dojdziesz do uruchomienia programu ...

Jest to, choć nie niemożliwe, o wiele mniej prawdopodobne w przypadku klas.

W przykładzie z tylko jednym pliku źródłowym, można również rozważyć użycie przestrzeni nazw anonimowego jako że ogranicza zakres deklaracji do pliku, więc osoby spoza pliku nie może uzyskać do nich dostęp (lub kolidować z nich) przez przypadek .

+0

Dziękujemy za zgłoszenie problemu, który może wystąpić podczas modyfikowania przestrzeni nazw w różnych plikach. –

Powiązane problemy