클래스의 네임 스페이스 + 함수 및 정적 메서드


290

관련 함수 집합이 있거나 작성하려고한다고 가정하겠습니다. 그들이 수학과 관련이 있다고 가정 해 봅시다. 조직적으로, 나는 :

  1. 이 함수를 작성하여 MyMath네임 스페이스에 넣고 다음을 통해 참조하십시오.MyMath::XYZ()
  2. 호출 된 클래스를 만들고이 MyMath메소드를 정적으로 만들고 유사하게 참조하십시오.MyMath::XYZ()

소프트웨어를 구성하는 수단으로 왜 다른 것을 선택해야합니까?


4
우선, 네임 스페이스는 클래스와 정적 메소드에 비해 언어에 더 최근에 추가되었습니다. 클래스와 정적 메소드는 "클래스가있는 C"라는 언어에서 사용되었습니다. 일부 프로그래머는 이전 기능에 더 익숙 할 수 있습니다. 다른 프로그래머는 오래된 컴파일러를 사용하고있을 수 있습니다. 그냥 내 $ .02
Rom

21
@Rom : "오래된 프로그래머"에 대해서는 맞지만 "오래된 컴파일러"에 대해서는 틀립니다. 네임 스페이스는 이온 이후 올바르게 컴파일되었습니다 (1998 년부터 Visual C ++ 6으로 작업했습니다!). "클래스가있는 C"에 관해서는,이 포럼의 일부 사람들은 그러한 상황이 발생했을 때조차 태어나지도 않았습니다. 결론적으로, 구식 C ++ 컴파일러 만 네임 스페이스를 지원하지 않습니다. 그것들을 사용하지 않는 변명으로 그 주장을 사용하지 마십시오.
paercebal

@paercebal : 일부 고대 컴파일러는 여전히 임베디드 세계에서 사용되고 있습니다. 네임 스페이스를 지원하지 않는 것은 아마도 모든 사람들이 매일 상호 작용하는 다양한 소형 CPU (스테레오, 전자 레인지, 자동차의 엔진 제어 장치, 신호등 등)에 대한 코드를 작성하는 동안 극복해야 할 가장 작은 불편 중 하나 일 것입니다. 명확하게 : 나는 더 나은 최신 컴파일러를 어디에서나 사용하지 않는 것을 옹호하지 않습니다. Au conrare : 저는 최신 언어 기능 (RTTI 제외)에 모두 동의합니다. 나는 그런 경향이 존재한다고 지적하고있다
Rom

13
@Rom : 현재의 경우, 문제의 저자는 선택권을 가지므로 분명히 어떤 컴파일러도 네임 스페이스가없는 코드를 컴파일하지 못합니다. 그리고 이것이 C ++에 대한 질문이므로 네임 스페이스 언급 및 필요한 경우 문제에 대한 RTTI 솔루션을 포함하여 C ++ 답변을 제공해야합니다. C 답변 또는 C-with-classes-for-obsolete-compilers 답변을 제공하는 것은 주제가 아닙니다.
paercebal

2
"단지 내 $ .02"-네임 스페이스를 지원하지 않는 현존하는 C ++ 컴파일러의 증거를 제공 한 경우 더 가치가 있습니다. "일부 고대 컴파일러는 여전히 임베디드 세계에서 사용되고있다"-이것은 어리석은 일이다. "임베디드 월드"는 C ++ 네임 스페이스보다 최신 개발입니다. "클래스가있는 C"는 누군가가 C 코드를 포함하기 훨씬 전에 1979 년에 도입되었습니다. "저는 그런 경향이 존재한다는 것을 지적하고 있습니다."-이 질문과는 아무 상관이 없습니다.
Jim Balter

답변:


243

기본적으로 네임 스페이스 함수를 사용하십시오.

클래스는 네임 스페이스를 대체하지 않고 객체를 빌드하는 것입니다.

객체 지향 코드에서

Scott Meyers는이 주제에 대한 "유효한 C ++ 책에 대한 전체 항목"을 작성했습니다. Herb Sutter의 기사 에서이 원칙에 대한 온라인 참조를 찾았습니다.http://www.gotw.ca/gotw/084.htm

알아야 할 중요한 사항은 다음과 같습니다 . 클래스와 동일한 네임 스페이스의 C ++ 함수에서 ADL 은 함수 호출을 해결할 때 해당 함수를 검색 하기 때문에 해당 클래스의 인터페이스에 속합니다 .

네임 스페이스 함수는 "friend"로 선언되지 않으면 클래스의 내부에 액세스 할 수 없지만 정적 메서드는 사용할 수 있습니다.

예를 들어 클래스를 유지 관리 할 때 클래스의 내부를 변경해야하는 경우 정적 메서드를 포함한 모든 메서드에서 부작용을 검색해야합니다.

확장 I

클래스 인터페이스에 코드 추가

C #에서는 액세스 권한이 없어도 클래스에 메서드를 추가 할 수 있습니다. 그러나 C ++에서는 불가능합니다.

그러나 여전히 C ++에서는 다른 사람이 작성한 클래스에도 네임 스페이스 함수를 추가 할 수 있습니다.

다른 측면에서 볼 때 이것은 코드를 디자인 할 때 중요합니다. 함수를 네임 스페이스에 배치하면 사용자가 클래스의 인터페이스를 늘리거나 완성 할 수있는 권한을 부여하기 때문입니다.

확장 II

이전 포인트의 부작용으로 여러 헤더에 정적 메소드를 선언 할 수 없습니다. 모든 메소드는 동일한 클래스에서 선언되어야합니다.

네임 스페이스의 경우 동일한 네임 스페이스의 함수를 여러 헤더에 선언 할 수 있습니다 (가장 표준 스왑 함수가 그 중 가장 좋은 예입니다).

확장 III

네임 스페이스의 기본 멋진 점은 일부 코드에서 "using"키워드를 사용하면 언급하지 않아도된다는 것입니다.

#include <string>
#include <vector>

// Etc.
{
   using namespace std ;
   // Now, everything from std is accessible without qualification
   string s ; // Ok
   vector v ; // Ok
}

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR

"오염"을 한 클래스로 제한 할 수도 있습니다.

#include <string>
#include <vector>

{
   using std::string ;
   string s ; // Ok
   vector v ; // COMPILATION ERROR
}

string ss ; // COMPILATION ERROR
vector vv ; // COMPILATION ERROR

이 "패턴"은 거의 표준 스왑 관용구를 올바르게 사용하기 위해 필수적입니다.

그리고 이것은 클래스의 정적 메소드로는 불가능합니다.

따라서 C ++ 네임 스페이스에는 고유 한 의미가 있습니다.

그러나 상속과 비슷한 방식으로 네임 스페이스를 결합 할 수 있으므로 더욱 발전합니다.

예를 들어 함수 AAA가 포함 된 네임 스페이스 A, 함수 BBB가 포함 된 네임 스페이스 B가있는 경우 네임 스페이스 C를 선언하고 using을 키워드로이 네임 스페이스에 AAA 및 BBB를 가져올 수 있습니다.

결론

네임 스페이스는 네임 스페이스를위한 것입니다. 수업은 수업을위한 것입니다.

C ++는 각 개념이 다르도록 서로 다른 문제에 대한 솔루션으로 다르게 사용되도록 설계되었습니다.

네임 스페이스가 필요할 때 클래스를 사용하지 마십시오.

그리고 귀하의 경우 네임 스페이스가 필요합니다.


이 답변을 스레드에도 적용 할 수 있습니까? 즉, 스레드에 정적 메소드보다 네임 스페이스를 사용하는 것이 더 낫습니까?
dashesy

3
@dashesy : 네임 스페이스 대 정적 메소드 는 스레드와 관련이 없으므로 네임 스페이스가 정적 메소드보다 거의 항상 낫기 때문에 네임 스페이스가 더 좋습니다. 한 가지 경우, 정적 메소드는 클래스 멤버 변수에 액세스 할 수 있으므로 네임 스페이스보다 캡슐화 값이 더 낮습니다. 그리고 스레드 실행에서 데이터 격리가 훨씬 중요합니다.
paercebal

@ paercebal- 덕분에 스레드 함수에 정적 클래스 메서드를 사용하고있었습니다. 이제 클래스를 네임 스페이스로 잘못 사용하고 있다는 것을 알고 있으므로 하나의 객체에 여러 스레드를 갖는 가장 좋은 방법은 무엇이라고 생각하십니까? 나는 또한이 질문을 너무 많이했다, 당신이 (여기 또는 질문 자체에서) 약간의 빛을 비출 수 있다면 감사합니다.
dashesy

1
@dashesy : 당신은 문제를 요구하고 있습니다. 다른 스레드에서 원하는 것은 공유하지 않아야하는 데이터를 격리하는 것이므로 클래스의 개인 데이터에 대한 특권 액세스 권한을 가진 여러 스레드를 갖는 것은 나쁜 생각입니다. 클래스 내에서 하나의 스레드를 숨기고 해당 스레드의 데이터를 기본 스레드의 데이터와 분리해야합니다. 물론 공유되어야하는 데이터는 해당 클래스의 구성원 일 수 있지만 여전히 동기화되어야합니다 (잠금, 원자 등). 액세스 할 수있는 라이브러리의 양이 확실하지 않지만 작업 / 비동기를 사용하는 것이 훨씬 좋습니다.
paercebal

paercebal의 대답은 받아 들여 져야합니다! 네임 스페이스 +
ADL-

54

나와 동의하지 않는 사람들이 많이 있지만 이것이 내가 보는 방식입니다.

클래스는 본질적으로 특정 종류의 객체에 대한 정의입니다. 정적 메소드는 해당 오브젝트 정의와 밀접하게 연관된 조작을 정의해야합니다.

기본 객체와 관련이없는 관련 함수 그룹 이나 객체 종류의 정의를 얻으 려면 네임 스페이스 만 사용한다고 말하고 싶습니다. 개념 상으로는이게 훨씬 더 합리적입니다.

예를 들어, 귀하의 경우, "MyMath 란 무엇입니까?" 경우 MyMath객체의 종류를 정의하지 않습니다, 그때 내가 말할 것이다 : 그것은 클래스하지 않습니다.

그러나 내가 말했듯이, (특히 Java 및 C # 개발자)에 대해 (심지어) 나에게 동의하지 않을 사람들이 많이 있다는 것을 알고 있습니다.


3
당신은 이것에 대해 매우 순수한 관점을 가지고 있습니다. 그러나 실질적으로 말해서, 모든 정적 메소드를 가진 클래스는 유용 할 수 typedef있습니다 . 여러분은 그것들을 템플릿 매개 변수로 사용할 수 있습니다.
Shog9

56
Jave와 C # 사람들은 선택의 여지가 없기 때문입니다.
Martin York

7
sho 함수도 템플릿화할 수 있습니다!
Martin York

6
@Dan : 아마도 수학 루틴이 필요하고 다른 구현을 "플러그인"하기를 원했던 것으로 추정됩니다.
Shog9

1
@Dan : "클래스를 템플릿 매개 변수로 사용하는 데 관심이 있다면, 그 클래스는 기본 객체를 정의하고있을 것입니다." 아뇨, 전혀 아닙니다. 특성을 생각하십시오. (그럼에도 불구하고, 나는 당신의 답변에 전적으로 동의합니다.)
sbi

18
  • 정적 데이터가 필요한 경우 정적 메소드를 사용하십시오.
  • 그것들이 템플릿 함수이고 모든 함수에 대해 템플릿 매개 변수 집합을 지정하려면 템플릿 클래스에서 정적 메서드를 사용하십시오.

그렇지 않으면 네임 스페이스 함수를 사용하십시오.


주석에 대한 응답으로 예, 정적 메소드 및 정적 데이터가 과도하게 사용되는 경향이 있습니다. 그렇기 때문에 도움이 될만한 두 가지 관련 시나리오 만 제공했습니다 . OP의 특정 예제 (수학 루틴 세트)에서 모든 루틴에 적용되는 매개 변수 (예 : 핵심 데이터 유형 및 출력 정밀도)를 지정하는 기능을 원하는 경우 다음과 같은 작업을 수행 할 수 있습니다.

template<typename T, int decimalPlaces>
class MyMath
{
   // routines operate on datatype T, preserving at least decimalPlaces precision
};

// math routines for manufacturing calculations
typedef MyMath<double, 4> CAMMath;
// math routines for on-screen displays
typedef MyMath<float, 2> PreviewMath;

그런 다음, 그 필요하지 않은 경우 모든 수단 네임 스페이스를 사용합니다.


2
소위 정적 데이터는 네임 스페이스의 구현 파일에서 네임 스페이스 레벨 데이터 일 수 있으며, 헤더에 표시 할 필요가 없기 때문에 커플 링이 훨씬 줄어 듭니다.
Motti

정적 데이터는 네임 스페이스 범위 전역보다 낫습니다.
coppro

@coppro. 그들은 개인이 될 수 있기 때문에 임의의 세계에서 진화 사슬을 적어도 한 단계 올립니다 (그렇지 않으면 동의하십시오).
Martin York

@Motti : OTOH, 헤더 (인라인 / 템플릿 기능)에서 원하는 경우 다시 못생긴 것입니다.
Shog9

1
재미있는 예, 반복되는 template주장 을 피하기 위해 클래스를 속기로 사용하십시오 !
underscore_d

13

네임 스페이스는 클래스에 비해 많은 장점이 있으므로 네임 스페이스를 사용해야합니다.

  • 동일한 헤더에서 모든 것을 정의 할 필요는 없습니다.
  • 헤더에 모든 구현을 노출시킬 필요는 없습니다.
  • 당신은 using반원 이 될 수 없습니다 ; using네임 스페이스 멤버 일 수 있습니다
  • 당신이 할 수는 없지만 using class, using namespace종종 좋은 생각은 아닙니다.
  • 클래스를 사용하면 실제로 아무것도 없을 때 만들 객체가 있음을 의미합니다.

제 생각에 정적 멤버는 매우 과도하게 사용됩니다. 대부분의 경우에 꼭 필요한 것은 아닙니다. 정적 멤버 함수는 아마도 파일 범위 함수로 더 나을 수 있으며 정적 데이터 멤버는 더 나은 가치가있는 글로벌 객체 일뿐입니다.


3
"헤더에 모든 구현을 공개 할 필요는 없습니다"클래스를 사용할 때도 마찬가지입니다.
Vanuan

또한 네임 스페이스를 사용하는 경우 헤더에 모든 구현을 표시 할 수 없습니다 (심볼의 다중 정의로 끝날 것입니다). 인라인 클래스 멤버 함수를 사용하면 그렇게 할 수 있습니다.
Vanuan

1
@Vanuan : 헤더에서 네임 스페이스 구현을 노출 할 수 있습니다. inline키워드를 사용하여 ODR을 충족하십시오.
Thomas Eding

@ThomasEding 필요하지 않습니다! = 수
Vanuan

3
@Vanuan :를 사용할 때 컴파일러가 보장하는 것은 한 가지 뿐이며 inline함수 본문을 "인라인"하지 않습니다. 의 실제 (그리고 표준에 의해 보장 된) 목적은 inline다중 정의를 방지하는 것입니다. C ++의 "하나의 정의 규칙"에 대해 읽으십시오. 또한 ODR 문제 대신 미리 컴파일 된 헤더 문제로 인해 연결된 SO 질문이 컴파일되지 않았습니다.
Thomas Eding

3

구현 파일의 익명 네임 스페이스에 개인 데이터를 가질 수있는 네임 스페이스를 선호합니다 (따라서 private멤버 와 달리 헤더에 전혀 표시 할 필요가 없습니다 ). 또 다른 이점은 using네임 스페이스에서 메소드의 클라이언트가 지정을 거부 할 수 있다는 것입니다MyMath::


2
클래스가있는 구현 파일의 익명 네임 스페이스에 개인 데이터를 가질 수도 있습니다. 내가 당신의 논리를 따르는 지 확실하지 않습니다.
Patrick Johnmeyer

0

클래스를 사용해야하는 또 하나의 이유-액세스 지정자를 사용하는 옵션입니다. 그런 다음 공개 정적 메소드를 더 작은 개인 메소드로 나눌 수 있습니다. 공용 메소드는 여러 개인 메소드를 호출 할 수 있습니다.


6
액세스 수정자는 멋지지만 대부분의 private방법 조차도 프로토 타입이 헤더에 전혀 게시되지 않아서 보이지 않는 방법보다 접근하기 쉽습니다. 익명의 네임 스페이스 기능으로 제공되는 더 나은 캡슐화에 대해서는 언급하지 않았습니다.
paercebal

2
개인 메서드는 IMO이며 구현에서 함수 자체를 숨기고 (cpp 파일) 헤더 파일에 노출시키지 않는 것보다 열등합니다. 귀하의 답변과 개인 회원을 선호하는 이유를 자세히 설명하십시오 . 그때까지 -1.
nonsensickle

@nonsensickle 아마도 그는 반복되는 섹션이 많은 매머드 기능이 안전하게 보호되지 않고 개인의 배후에있는 하위 섹션을 숨기고 다른 사람들이 위험하거나 매우주의해서 사용해야하는 경우 해당 섹션에 도달하지 못하게 할 수 있음을 의미합니다.
Troyseph

1
@Troyseph조차도 .cpp파일 의 이름없는 네임 스페이스 안에이 정보를 숨길 수 있으므로 헤더 파일을 읽는 사람에게 불필요한 정보를 제공하지 않고도 해당 번역 단위에 비공개로 만들 수 있습니다. 효과적으로, 나는 PIMPL 관용구를 옹호하려고합니다.
nonsensickle

.cpp템플릿을 사용하려면 파일에 넣을 수 없습니다 .
Yay295

0

네임 스페이스와 클래스 메서드는 모두 용도가 있습니다. 네임 스페이스는 여러 파일로 분산 될 수 있지만 모든 관련 코드를 한 파일로 강제로 적용해야하는 경우에는 약합니다. 위에서 언급했듯이 클래스를 사용하면 클래스에서 개인 정적 멤버를 만들 수도 있습니다. 구현 파일의 익명 네임 스페이스에 사용할 수 있지만 클래스 내부에있는 것보다 여전히 더 큰 범위입니다.


"구현 파일의 익명 네임 스페이스에 [저장하는 것]은 클래스 내부에있는 것보다 더 큰 범위입니다."-아닙니다. 멤버에 대한 특권 액세스가 필요하지 않은 경우, 익명으로 네임 스페이스 된 것 보다 익명으로 네임 스페이스 된 것 private:입니다. 많은 경우에 특권 액세스 가 필요한 것처럼 보일 수 있습니다. 가장 '비공개'기능은 헤더에 나타나지 않는 기능입니다. private:메소드는이 이점을 결코 누릴 수 없습니다.
underscore_d
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.