[C++] 헤더 파일에 있는 struct를 리턴할 경우 궁금한 사항이 있습니다.
글쓴이: bellfive2000 / 작성시간: 수, 2016/07/13 - 7:30오후
아래와 같은 경우
//<header> struct PageCache { PageCache(); ~PageCache(); struct Page { void *mData; int mSize; int mOffset; ~Page(); }; int made; Page* acquirePage(); }; //<c++> #include "PageCache.h" PageCache::PageCache() { made = 0; } PageCache::~PageCache() { } PageCache::Page* PageCache::acquirePage() { //<== 해당 부분을 Page*로 리턴하게 하면 에러 발생 Page* page; return page; }
acquirePage란 함수에서 리턴값을 풀(PageCache::Page)로 써줘야만 compile 에러가 발생하지 않는 이유가 궁금합니다.
함수 내부에 있는 Page* page의 경우는 생략해서 쓸수 있는것에 비교했을 때 이상합니다.
물론 헤더 파일도 생략이 가능하네요.
얼핏 생각했을 땐 header의 경우는 Page struct 를 직접적으로 알 수 있기 때문에 생략 가능하다고 보여지는데
cpp는 여러 header들이 참조할 수 있기 때문에 풀로 써줘야 하나? 싶다가도 앞서 언급드린 함수 내부에서는 또 생략이 가능하기 때문에 헷갈리네요.
구글링해도 못 찾아 궁금한 점 올립니다.
Forums:
Aㅏ...
방금 전에 "포인터에
const
를 어떻게 붙였을 때 어떤 의미인가" 라는 비교적 간단한 문제에 답글 쓴답시고 C언어 선언 문법을 독해하며 시간을 들이붓고 왔는데 이번엔 이런 문제가... -_-;;말씀하신 것과 같은 문제, 즉 그러니까,
네임스페이스 안의 네임스페이스 안의 클래스 안의 클래스 따위의 계층적인 구조를 만들 수 있는 C++에서 어떤 이름을 썼을 때 그 이름에 대응하는 선언을 어디서 찾냐,
하는 문제를, C++ 표준에서는 "Name lookup"이라고 합니다.
그 중에서 Scope resolution operator ::를 끼고 있는 이름을 찾는 걸 Qualified name lookup, 안 끼고 있는 이름을 찾는 건 Unqualified name lookup이라고 하고요,
지금 질문 내용은 Unqualified name인 "Page"를 써도 문제 없는 상황을 추려내 달라고 하시는 건데, 표준에서 이걸 설명하는 내용이 말 그대로 case-by-case로 전부 나열하는 거에요. 6페이지에 달합니다. (저는 지금 C++11 표준을 보고 있습니다.)
이걸 다 번역해드리기도 어렵고, 필요한 부분만 발췌해서 번역해드리기도 어렵고, 거 참 힘드네요. -_-;;; 정말로 딱 필요한 부분만 뽑겠습니다.
1. 헤더 파일의
Page* acquirePage();
는 사용자 정의 클래스PageCache
의 정의 안에 있으면서 멤버 함수 몸체나 중첩 클래스 정의 밖에 있는데요.이 경우 Unqualified name인
Page
는 클래스PageCache
에서 "사용되기 전에 선언"되어 있으면 그것을 우선적으로 선택합니다. 즉 원하시는PageCache::Page
를 정확히 고르게 됩니다.2. 소스 파일에서는 전역 범위에서
PageCache::acquirePage()
멤버 함수를 정의하고 있는데요. 여기서 한 가지 기준이 있습니다.(1) 멤버 함수의 declarator-id, 그러니까 이 경우엔 쉽게 말해서
PageCache::acquirePage
부분 뒤에서 사용되는 Unqualified name은,(i)일단 그 멤버함수 정의에서 해당 사용 전에 선언이 있다면 그걸 먼저 고릅니다.
(ii)그런 선언이 없죠. 그러면 멤버 함수가 속한 클래스(이 경우엔
PageCache
) 안에 해당하는 이름이 선언되어 있는지 봅니다. 여기서 탐색이 성공하고,PageCache::Page
를 찾게 됩니다.(2) declarator-id 뒤에 있지 않은 이름은, 이 경우엔 그냥 전역 범위에 있는 것으로 보고, 전역 범위에 선언되었는지 봅니다. 없으면 바로 실패합니다.
이제 아시겠나요?
PageCache::acquirePage()
멤버 함수 정의에서 반환값 타입 이름으로 쓰인Page
는 전역 범위에서 사용되었다고 보고 (2)를 적용하여 탐색이 실패하는 겁니다.반면 멤버 함수 본체에 있는
Page* page;
는 (1)이 적용되어 무사히 탐색이 끝나고PageCache::Page
에 대응됩니다.이게 제가 할 수 있는 최선입니다.
설명이 모자란 거 저도 알아요. 근데 더 쉽고 유익하게 설명해주실 수 있는 분이 계시면 저도 그 분 답글 읽고 싶네요.
표준을 직접 읽고 해설해드리는 거 너무 어렵습니다.
덧. C++의 Name lookup 규칙은 뭐
덧.
C++의 Name lookup 규칙은 뭐 나름대로 합리적이긴 합니다만 모든 해괴한 케이스들에 대해서 올바르게 해석하려면 결국 휴먼 컴파일러가 될 수밖에 없습니다. 문법을 죄다 암기하고 적용하는 수밖에...
그리고 이걸 죄다 외우는 건 C언어의 declarator 문법을 다 외우는 것에 버금갈 정도로 힘들 것 같아요. 과연 오래 하다보면 체득이 될지 안될지는 솔직히 잘 모르겠네요.
또 덧붙이자면, C++03 declarator 문법은 C언어의 그것보다 훨씬 어렵습니다. C++11 declarator 문법은 C++03의 그것보다 훨씬 어렵고요.
설명 감사합니다 ^^
굉장히 자세한 설명..^^
그리고 실제 저도 이런 문제에 정리할 기회가 있었는데 실제 이렇게 쓰기 귀찮기도 하고 어렵기도 한데 잘 설명해주셔서 감사합니다.
말씀하신대로 어려운 문제라서 지금 댓글을 읽어도 아주 클리어하게 이해가 된다고 보기 어렵긴하네요 ^________^
C++ 스펙 문서에서 못 찾고 있었는데 이젠 키워드로 찾아서 볼 수 있겠네요 그것도 정말 감사드립니다~~
댓글 달기