네임스페이스 (C++)Namespaces (C++)

네임스페이스는 내부 식별자(형식, 함수, 변수 등의 이름)에 범위를 제공하는 선언적 영역입니다.A namespace is a declarative region that provides a scope to the identifiers (the names of types, functions, variables, etc) inside it. 네임스페이스는 코드를 논리 그룹으로 구성하고 특히 코드베이스에 여러 라이브러리가 포함된 경우 발생할 수 있는 이름 충돌을 방지하는 데 사용됩니다.Namespaces are used to organize code into logical groups and to prevent name collisions that can occur especially when your code base includes multiple libraries. 네임스페이스 범위에 있는 모든 식별자는 한정 없이 서로에게 표시됩니다.All identifiers at namespace scope are visible to one another without qualification. 네임 스페이스 외부의 식별자는 각 식별자에 대 한 정규화 된 이름 (예:)을 사용 하 여 멤버에 액세스 하거나, 단일 식별자에 대 한 using std::vector<std::string> vec; 선언 ( using std::string ) 또는 네임 스페이스의 모든 식별자에 대 한 using 지시문 ()을 사용 하 여 멤버에 액세스할 수 있습니다 using namespace std; .Identifiers outside the namespace can access the members by using the fully qualified name for each identifier, for example std::vector<std::string> vec;, or else by a using Declaration for a single identifier (using std::string), or a using Directive for all the identifiers in the namespace (using namespace std;). 헤더 파일의 코드는 항상 정규화된 네임스페이스 이름을 사용해야 합니다.Code in header files should always use the fully qualified namespace name.

다음 예제에서는 네임스페이스 선언 및 네임스페이스 외부 코드가 해당 멤버에 액세스할 수 있는 세 가지 방법을 보여 줍니다.The following example shows a namespace declaration and three ways that code outside the namespace can accesses their members.

namespace ContosoData
{
    class ObjectManager
    {
    public:
        void DoSomething() {}
    };
    void Func(ObjectManager) {}
}

정규화된 이름 사용:Use the fully qualified name:

ContosoData::ObjectManager mgr;
mgr.DoSomething();
ContosoData::Func(mgr);

using 선언을 사용하여 하나의 식별자를 범위로 가져오기:Use a using declaration to bring one identifier into scope:

using ContosoData::ObjectManager;
ObjectManager mgr;
mgr.DoSomething();

using 지시문을 사용하여 네임스페이스의 모든 식별자를 범위로 가져오기:Use a using directive to bring everything in the namespace into scope:

using namespace ContosoData;

ObjectManager mgr;
mgr.DoSomething();
Func(mgr);

using 지시문using directives

using 지시문을 namespace 사용 하면 명시적 한정자로 네임 스페이스 이름 없이의 모든 이름을 사용할 수 있습니다.The using directive allows all the names in a namespace to be used without the namespace-name as an explicit qualifier. 네임 스페이스에서 여러 다른 식별자를 사용 하는 경우 구현 파일 (예: * .cpp)에서 using 지시문을 사용 합니다. 하나 또는 두 개의 식별자만 사용 하는 경우에는 using 선언을 사용 하 여 네임 스페이스의 모든 식별자가 아닌 해당 식별자를 범위로 가져옵니다.Use a using directive in an implementation file (i.e. *.cpp) if you are using several different identifiers in a namespace; if you are just using one or two identifiers, then consider a using declaration to only bring those identifiers into scope and not all the identifiers in the namespace. 지역 변수의 이름이 네임스페이스 변수와 동일한 경우 네임스페이스 변수가 숨겨집니다.If a local variable has the same name as a namespace variable, the namespace variable is hidden. 전역 변수와 동일한 이름을 가진 네임스페이스 변수를 사용하면 오류가 발생합니다.It is an error to have a namespace variable with the same name as a global variable.

참고

using 지시문은 .cpp 파일 맨 위나(파일 범위) 클래스 또는 함수 정의 내에 배치할 수 있습니다.A using directive can be placed at the top of a .cpp file (at file scope), or inside a class or function definition.

일반적으로 헤더 파일(*.h)에는 using 지시문을 넣지 마세요. 해당 헤더를 포함하는 모든 파일이 네임스페이스의 모든 식별자를 범위로 가져오기 때문에 이름 숨김 및 이름 충돌 문제가 발생할 수 있으며, 디버그하기 매우 어렵습니다.In general, avoid putting using directives in header files (*.h) because any file that includes that header will bring everything in the namespace into scope, which can cause name hiding and name collision problems that are very difficult to debug. 헤더 파일에는 항상 정규화된 이름을 사용하세요.Always use fully qualified names in a header file. 이름이 너무 길면 네임스페이스 별칭을 사용하여 축약할 수 있습니다.If those names get too long, you can use a namespace alias to shorten them. 다음을 참조하세요.(See below.)

네임스페이스 및 네임스페이스 멤버 선언Declaring namespaces and namespace members

일반적으로 헤더 파일에서 네임스페이스를 선언합니다.Typically, you declare a namespace in a header file. 함수 구현이 별도 파일에 있는 경우 이 예제와 같이 함수 이름을 한정합니다.If your function implementations are in a separate file, then qualify the function names, as in this example.

//contosoData.h
#pragma once
namespace ContosoDataServer
{
    void Foo();
    int Bar();
}

Contosodata의 함수 구현에서는 using 지시문을 파일의 맨 위에 둔 경우에도 정규화 된 이름을 사용 해야 합니다.Function implementations in contosodata.cpp should use the fully qualified name, even if you place a using directive at the top of the file:

#include "contosodata.h"
using namespace ContosoDataServer;

void ContosoDataServer::Foo() // use fully-qualified name here
{
   // no qualification needed for Bar()
   Bar();
}

int ContosoDataServer::Bar(){return 0;}

단일 파일의 여러 블록과 여러 파일에서 네임스페이스를 선언할 수 있습니다.A namespace can be declared in multiple blocks in a single file, and in multiple files. 컴파일러가 전처리 중에 파트를 결합하며, 결과로 생성된 네임스페이스에는 모든 파트에서 선언된 멤버가 모두 포함됩니다.The compiler joins the parts together during preprocessing and the resulting namespace contains all the members declared in all the parts. 이러한 예로 표준 라이브러리의 각 헤더 파일에서 선언된 std 네임스페이스가 있습니다.An example of this is the std namespace which is declared in each of the header files in the standard library.

정의된 이름의 명시적 정규화로 선언된 명명된 네임스페이스의 멤버는 해당 네임스페이스의 외부에서 정의될 수 있습니다.Members of a named namespace can be defined outside the namespace in which they are declared by explicit qualification of the name being defined. 그러나 정의는 선언의 네임스페이스를 포함하는 네임스페이스의 선언 위치 다음에 표시되어야 합니다.However, the definition must appear after the point of declaration in a namespace that encloses the declaration's namespace. 예를 들어:For example:

// defining_namespace_members.cpp
// C2039 expected
namespace V {
    void f();
}

void V::f() { }        // ok
void V::g() { }        // C2039, g() is not yet a member of V

namespace V {
    void g();
}

이 오류는 여러 헤더 파일에서 네임스페이스 멤버가 선언되었으며 해당 헤더를 올바른 순서로 포함하지 않은 경우에 발생할 수 있습니다.This error can occur when namespace members are declared across multiple header files, and you have not included those headers in the correct order.

전역 네임스페이스The global namespace

식별자가 명시적 네임스페이스에서 선언되지 않은 경우 암시적 전역 네임스페이스에 포함됩니다.If an identifier is not declared in an explicit namespace, it is part of the implicit global namespace. 일반적으로 전역 네임 스페이스에 있어야 하는 진입점 Main 함수를 제외 하 고 가능 하면 전역 범위에서 선언을 만들지 마십시오.In general, try to avoid making declarations at global scope when possible, except for the entry point main Function, which is required to be in the global namespace. 전역 식별자를 명시적으로 한정하려면 ::SomeFunction(x);과 같이 범위 확인 연산자를 이름 없이 사용합니다.To explicitly qualify a global identifier, use the scope resolution operator with no name, as in ::SomeFunction(x);. 이렇게 하면 다른 네임스페이스에 있는 동일한 이름의 식별자와 해당 식별자가 구분되며, 다른 사용자가 코드를 더 쉽게 이해하는 데에도 도움이 됩니다.This will differentiate the identifier from anything with the same name in any other namespace, and it will also help to make your code easier for others to understand.

std 네임스페이스The std namespace

모든 c + + 표준 라이브러리 형식 및 함수는 std 내부에 중첩 된 네임 스페이스 또는 네임 스페이스에서 선언 됩니다 std .All C++ standard library types and functions are declared in the std namespace or namespaces nested inside std.

중첩된 네임스페이스Nested namespaces

네임스페이스를 중첩할 수 있습니다.Namespaces may be nested. 일반적인 중첩 된 네임 스페이스는 부모 멤버에 대 한 정규화 되지 않은 액세스를 갖지만, 부모 멤버는 다음 예제와 같이 인라인으로 선언 되지 않는 한 중첩 된 네임 스페이스에 대 한 정규화 되지 않은 액세스 권한을 갖지 않습니다.An ordinary nested namespace has unqualified access to its parent's members, but the parent members do not have unqualified access to the nested namespace (unless it is declared as inline), as shown in the following example:

namespace ContosoDataServer
{
    void Foo();

    namespace Details
    {
        int CountImpl;
        void Ban() { return Foo(); }
    }

    int Bar(){...};
    int Baz(int i) { return Details::CountImpl; }
}

일반적인 중첩된 네임스페이스를 사용하여 부모 네임스페이스의 공용 인터페이스에 포함되지 않는 내부 구현 세부 정보를 캡슐화할 수 있습니다.Ordinary nested namespaces can be used to encapsulate internal implementation details that are not part of the public interface of the parent namespace.

인라인 네임스페이스(C++ 11)Inline namespaces (C++ 11)

일반적인 중첩된 네임스페이스와 달리, 인라인 네임스페이스의 멤버는 부모 네임스페이스의 멤버로 처리됩니다.In contrast to an ordinary nested namespace, members of an inline namespace are treated as members of the parent namespace. 이러한 특징 때문에 오버로드된 함수의 인수 종속 조회가 부모 및 중첩된 인라인 네임스페이스에 오버로드가 있는 함수에서 작동할 수 있습니다.This characteristic enables argument dependent lookup on overloaded functions to work on functions that have overloads in a parent and a nested inline namespace. 또한 인라인 네임스페이스에서 선언된 템플릿의 부모 네임스페이스에서 특수화를 선언할 수 있습니다.It also enables you to declare a specialization in a parent namespace for a template that is declared in the inline namespace. 다음 예제에서는 외부 코드가 기본적으로 인라인 네임스페이스에 바인딩하는 방법을 보여 줍니다.The following example shows how external code binds to the inline namespace by default:

//Header.h
#include <string>

namespace Test
{
    namespace old_ns
    {
        std::string Func() { return std::string("Hello from old"); }
    }

    inline namespace new_ns
    {
        std::string Func() { return std::string("Hello from new"); }
    }
}

#include "header.h"
#include <string>
#include <iostream>

int main()
{
    using namespace Test;
    using namespace std;

    string s = Func();
    std::cout << s << std::endl; // "Hello from new"
    return 0;
}

다음 예제에서는 인라인 네임스페이스에서 선언된 템플릿의 부모에서 특수화를 선언할 수 있는 방법을 보여 줍니다.The following example shows how you can declare a specialization in a parent of a template that is declared in an inline namespace:

namespace Parent
{
    inline namespace new_ns
    {
         template <typename T>
         struct C
         {
             T member;
         };
    }
     template<>
     class C<int> {};
}

인라인 네임스페이스를 버전 관리 메커니즘으로 사용하여 라이브러리의 공용 인터페이스에 대한 변경 내용을 관리할 수 있습니다.You can use inline namespaces as a versioning mechanism to manage changes to the public interface of a library. 예를 들어 단일 부모 네임스페이스를 만들고 인터페이스의 각 버전을 부모 안에 중첩된 자체 네임스페이스에 캡슐화할 수 있습니다.For example, you can create a single parent namespace, and encapsulate each version of the interface in its own namespace nested inside the parent. 가장 최근 버전이나 기본 설정 버전을 보유한 네임스페이스는 인라인으로 한정되므로 부모 네임스페이스의 직접 멤버인 것처럼 노출됩니다.The namespace that holds the most recent or preferred version is qualified as inline, and is therefore exposed as if it were a direct member of the parent namespace. Parent::Class를 호출하는 클라이언트 코드는 자동으로 새 코드에 바인딩합니다.Client code that invokes the Parent::Class will automatically bind to the new code. 이전 버전을 사용하려는 클라이언트는 해당 코드가 있는 중첩된 네임스페이스의 정규화된 경로를 사용하여 계속 액세스할 수 있습니다.Clients that prefer to use the older version can still access it by using the fully qualified path to the nested namespace that has that code.

컴파일 단위에서 네임스페이스의 첫 번째 선언에 Inline 키워드를 적용해야 합니다.The inline keyword must be applied to the first declaration of the namespace in a compilation unit.

다음 예제에서는 각각 중첩된 네임스페이스에 있는 각 인터페이스의 두 버전을 보여 줍니다.The following example shows two versions of an interface, each in a nested namespace. v_20 네임스페이스는 v_10 인터페이스에서 약간 수정되었으며 인라인으로 표시됩니다.The v_20 namespace has some modification from the v_10 interface and is marked as inline. 새 라이브러리를 사용하고 Contoso::Funcs::Add를 호출하는 클라이언트 코드는 v_20 버전을 호출합니다.Client code that uses the new library and calls Contoso::Funcs::Add will invoke the v_20 version. 코드에서 Contoso::Funcs::Divide를 호출하려고 하면 이제 컴파일 타임 오류가 발생합니다.Code that attempts to call Contoso::Funcs::Divide will now get a compile time error. 해당 함수가 실제로 필요한 경우 명시적으로 Contoso::v_10::Funcs::Divide를 호출하여 v_10 버전에 계속 액세스할 수 있습니다.If they really need that function, they can still access the v_10 version by explicitly calling Contoso::v_10::Funcs::Divide.

namespace Contoso
{
    namespace v_10
    {
        template <typename T>
        class Funcs
        {
        public:
            Funcs(void);
            T Add(T a, T b);
            T Subtract(T a, T b);
            T Multiply(T a, T b);
            T Divide(T a, T b);
        };
    }

    inline namespace v_20
    {
        template <typename T>
        class Funcs
        {
        public:
            Funcs(void);
            T Add(T a, T b);
            T Subtract(T a, T b);
            T Multiply(T a, T b);
            std::vector<double> Log(double);
            T Accumulate(std::vector<T> nums);
      };
    }
}

네임 스페이스 별칭Namespace aliases

네임스페이스 이름은 고유해야 하며, 이는 대체로 이름이 너무 짧지 않아야 함을 의미합니다.Namespace names need to be unique, which means that often they should not be too short. 이름 길이를 사용 하 여 코드를 읽을 수 없거나 using 지시문을 사용할 수 없는 헤더 파일을 입력 하는 것이 지루한 경우 실제 이름의 약어 역할을 하는 네임 스페이스 별칭을 만들 수 있습니다.If the length of a name makes code difficult to read, or is tedious to type in a header file where using directives can't be used, then you can make a namespace alias which serves as an abbreviation for the actual name. 예를 들어:For example:

namespace a_very_long_namespace_name { class Foo {}; }
namespace AVLNN = a_very_long_namespace_name;
void Bar(AVLNN::Foo foo){ }

익명 또는 명명되지 않은 네임스페이스anonymous or unnamed namespaces

명시적 네임스페이스를 만들고 이름을 지정하지 않을 수 있습니다.You can create an explicit namespace but not give it a name:

namespace
{
    int MyFunc(){}
}

이를 명명 되지 않은 네임 스페이스 또는 익명 네임 스페이스 라고 하며, 명명 된 네임 스페이스를 만들지 않고도 다른 파일 (즉, 내부 링크 제공)에서 코드에 대 한 변수 선언을 표시 하지 않으려는 경우에 유용 합니다.This is called an unnamed or anonymous namespace and it is useful when you want to make variable declarations invisible to code in other files (i.e. give them internal linkage) without having to create a named namespace. 동일한 파일의 모든 코드에서 명명되지 않은 네임스페이스의 식별자를 볼 수 있지만, 해당 파일 외부 또는 보다 정확히 말해 변환 단위 외부에서는 네임스페이스 자체와 함께 식별자를 볼 수 없습니다.All code in the same file can see the identifiers in an unnamed namespace but the identifiers, along with the namespace itself, are not visible outside that file—or more precisely outside the translation unit.

참고 항목See also

선언 및 정의Declarations and Definitions