C++에서 정규 이름 조회(qualified lookup)는 이름이 어떤 스코프(scope)에 속하는지를 명시적으로 지정하여, 해당 이름이 참조하는 객체나 함수를 결정하는 중요한 과정입니다. 이름 앞에 특정 스코프를 지정함으로써 컴파일러가 정확히 어떤 것을 참조해야 하는지 알 수 있습니다.
1. 정규 이름 조회와 비정규 이름 조회 비교
- 정규 이름 조회 (Qualified Lookup): 특정 네임스페이스, 클래스, 또는 범위를 명시적으로 지정하여 이름을 조회하는 방식입니다. 예를 들어 std::cout, ns::value, Base::function() 등에서 ::나 . 뒤에 붙는 범위를 통해 컴파일러가 정확한 스코프를 파악합니다.
- 비정규 이름 조회 (Unqualified Lookup): 함수나 변수의 이름만 사용하여, 컴파일러가 현재 스코프에서부터 상위 스코프까지 순차적으로 탐색하는 방식입니다. 예를 들어, 함수 내에서 value라는 변수를 조회할 때, 비정규 이름 조회는 가장 가까운 스코프부터 시작해 해당 이름을 찾습니다.
2. 기본 개념과 스코프
정규 이름 조회가 어떻게 스코프를 따라가는지 살펴보겠습니다.
- 스코프 (Scope): 변수, 함수, 클래스 등의 이름은 특정한 스코프에서만 유효합니다. 예를 들어, 함수 내부에서 정의된 변수는 해당 함수 내에서만 접근할 수 있습니다.
- 정규 이름 조회 순서:
- 현재 스코프: 지정한 범위 내에서 우선적으로 이름을 찾습니다. (예: 네임스페이스 ns::value 또는 클래스 Base::function 등)
- 외부 스코프: 지정한 범위 내에서 찾을 수 없을 경우, 외부 스코프(상위 스코프)에서 계속 찾습니다.
- 전역 스코프: 모든 스코프에서 찾지 못한 경우, 최종적으로 전역 스코프를 탐색하여 해당 이름을 찾습니다.
- 네임스페이스와 정규 이름 조회: 네임스페이스 안에 정의된 이름을 참조할 때 정규 이름 조회를 통해 명확히 지정할 수 있습니다. 이는 코드의 가독성을 높이고, 이름 충돌을 방지하는 데 유용합니다.
3. 예제
#include <iostream>
namespace ns {
int value = 42;
}
void function() {
int value = 10;
std::cout << value << std::endl; // 비정규 이름 조회: 현재 스코프에서 value(10) 참조
std::cout << ::value << std::endl; // 정규 이름 조회: 전역 스코프의 value 참조 (10)
std::cout << ns::value << std::endl; // 정규 이름 조회: 네임스페이스 ns의 value 참조 (42)
}
int main() {
function();
return 0;
}
위 예제에서 function() 함수 내의 value는 먼저 현재 스코프에 정의된 int value = 10을 참조합니다. ::value는 전역 스코프를 명확히 지정한 정규 이름 조회로 전역의 value를 참조하며, ns::value는 ns 네임스페이스 내의 value를 참조합니다.
4. 정규 이름 조회와 클래스 멤버
정규 이름 조회는 클래스의 정적 멤버(static member)나 상속받은 멤버 함수에 접근할 때도 사용됩니다.
예제 (상속 클래스에서 정규 이름 조회 사용)
#include <iostream>
class Base {
public:
static void greet() {
std::cout << "Hello from Base!" << std::endl;
}
};
class Derived : public Base {
public:
void callBaseGreet() {
Base::greet(); // 정규 이름 조회를 통해 기본 클래스 Base의 greet() 호출
}
};
int main() {
Derived d;
d.callBaseGreet();
return 0;
}
여기서 Base::greet()는 정규 이름 조회를 통해 명확히 기본 클래스의 greet()를 호출합니다. 이를 통해 클래스 계층에서 명확한 함수 호출이 가능해지며, 혼동을 방지할 수 있습니다.
5. 중첩된 네임스페이스에서의 정규 이름 조회
중첩된 네임스페이스에서도 정규 이름 조회는 유효합니다. 예를 들어, 네임스페이스가 중첩된 경우 Outer::Inner::name 형식으로 접근합니다.
#include <iostream>
namespace Outer {
namespace Inner {
void display() {
std::cout << "Hello from Inner namespace!" << std::endl;
}
}
}
int main() {
Outer::Inner::display(); // 중첩 네임스페이스에서 정규 이름 조회 사용
return 0;
}
이처럼 중첩 네임스페이스를 사용하면 코드를 더 구조화할 수 있으며, 명확한 조회 방식으로 오류를 줄일 수 있습니다.
6. using 지시어와 정규 이름 조회
using 지시어를 사용하면 특정 네임스페이스의 이름을 현재 스코프에서 직접 사용할 수 있습니다. 이는 네임스페이스를 명시하지 않고도 해당 스코프 내의 이름을 사용할 수 있게 해줍니다.
#include <iostream>
namespace ns {
void greet() {
std::cout << "Hello from ns!" << std::endl;
}
}
using namespace ns;
int main() {
greet(); // ns::greet()를 직접 호출할 수 있게 됨 (비정규 이름 조회)
return 0;
}
using namespace ns;를 사용하면 greet()를 네임스페이스를 명시하지 않고 호출할 수 있습니다. 그러나 using 지시어가 많아지면 이름 충돌의 가능성이 생기므로 주의해야 합니다.
7. 정규 이름 조회의 주의 사항
- 중복 이름: 여러 스코프에 동일한 이름이 존재할 때, 정규 이름 조회를 통해 명확히 참조하지 않으면 의도치 않은 이름을 참조할 수 있습니다.
- 선언과 정의: 정규 이름 조회를 사용하려면, 해당 이름이 선언되고 정의된 스코프를 정확히 알고 있어야 합니다. 이를 통해 코드의 가독성과 유지 보수성을 높일 수 있습니다.
'C++' 카테고리의 다른 글
[C++] std 네임스페이스 (0) | 2024.11.05 |
---|---|
[C++] this-> 접두사 (1) | 2024.11.04 |
[C++] 자격 없는 이름 (Unqualified Name) (0) | 2024.10.28 |
[C++] 네임스페이스(namespace) (0) | 2024.10.27 |
[C++] 중첩 호출(nested call) (0) | 2024.10.25 |