2009-05-30 3 views
7

나는이 질문을하게하는 연결된 질문 인 reading이었다.중첩 된 함수는 허용되지 않지만 중첩 된 함수 프로토 타입이 허용되는 이유는 무엇입니까? [C++]

모든 말한다

int main() 
{ 
    string SomeString(); 
} 

는, 컴파일러는 함수의 프로토 타입이 아닌 문자열 개체로이 소요 다음 코드를 고려하십시오. 이제 다음 코드를 살펴보십시오.

int main() 
{ 
    string Some() 
    { 
     return ""; 
    } 
} 

중첩 된 함수 정의가 허용되지 않으므로 컴파일러에서 유효하지 않습니다. 허용되지 않는 경우 중첩 된 함수 프로토 타입이 허용되는 이유는 무엇입니까? 혼란을 만들기보다는 어떤 이점도주지 않습니다 (또는 여기에 몇 가지 유효한 포인트가 누락 되었습니까?).

다음 내용이 유효하다는 것을 알았습니다.

int main() 
{ 
    string SomeFun(); 
    SomeFun(); 
    return 0; 
} 

string SomeFun() 
{ 
    std::cout << "WOW this is unexpected" << std::endl; 
} 

이것은 혼란 스럽습니다. 기능을 기대하고 있었는데 SomeFun()메인의 범위를 가질 것입니다. 그러나 나는 틀렸다. 왜 컴파일러는 위와 같은 코드를 컴파일 할 수 있습니까? 위와 같은 코드가 의미있는 실시간 상황이 있습니까?

의견이 있으십니까?

+0

+1 동일한 검색어 만 누르면 아래 답변에 모든 정보가 포함됩니다. – slashmais

답변

8

프로토 타입은 'Forward Declaration'입니다. Wikipedia 기사를 확인하십시오.

기본적으로 컴파일러에 은 "SomeFun '이라는 레이블이 이런 방식으로 사용되면 경고하지 않습니다."하지만 링커가 올바른 함수 몸체를 찾는 책임이 있습니다.

가짜 프로토 타입을 실제로 선언 할 수 있습니다 (예 : 'Char SomeFun()'을 사용하고 모든 것을 메인 위에 사용하십시오. 링커가 가짜 함수의 본문을 찾으려고 할 때만 오류가 발생합니다. 하지만 컴파일러는 멋질 것입니다.

많은 이점이 있습니다. 함수 본문이 항상 같은 소스 코드 파일에있는 것은 아님을 기억해야합니다. 또한 링크 된 라이브러리에있을 수 있습니다. 또한 링크 된 라이브러리에는 특정 '링크 서명'이있을 수 있습니다. 조건부 정의를 사용하면 빌드 할 때 범위가 지정된 프로토 타입을 사용하여 올바른 링크 서명을 선택할 수도 있습니다. 대부분의 사람들이 함수 포인터를 그 대신에.

희망이 도움이됩니다.

5

이것은 C와 같은 개념입니다. C++이 채택한 것과 마찬가지입니다.

C에서 다른 함수 내에서 함수를 선언 할 수있는 능력은 대부분의 프로그래머가 아마 유감스럽게 생각하는 결정입니다. 특히 함수 정의가 C보다 비교적 작은 현대 OOP 디자인의 경우

다른 함수의 범위에만있는 함수를 원하면 두 개의 옵션이 boost::lambdaC++1x lambda입니다.

3

함수 프로토 타입은 컴파일러의 경우 힌트입니다.그것들은 함수가 다른 곳에서 구현되었다는 것을 나타냅니다. 아직없는 경우 입니다. 아무것도 더.

3

프로토 타입을 선언 할 때 기본적으로 컴파일러에서 링커가이를 해결할 때까지 기다리라고 지시하고 있습니다. 프로토 타입을 작성하는 위치에 따라 범위 지정 규칙이 적용됩니다. main() 함수 안에서 프로토 타입을 작성하는 것은 기술적으로 잘못이 아닙니다. (비록 IMHO가 조금 복잡하지만) 함수가 main() 내부에서만 국한되어 있다는 것을 의미합니다. 프로토 타입을 소스 파일의 맨 위에 (또는 더 일반적으로 헤더 파일에) 선언하면 프로토 타입/함수는 전체 소스에서 알 수 있습니다.

string foo() 
{ 
    string ret = someString(); // Error 
    return ret; 
} 

int main(int argc,char**argv) 
{ 
    string someString(); 
    string s = somestring(); // OK 
    ... 
} 
7

부수적으로 C++ 03은 로터리 방식으로 로컬 함수를 정의합니다. 로컬로 선언을 계속하는 경우

void f() { 
    void g(); g(); 
} 

당신의 선언 그것은 일반적으로 좋은이 하나

void g(); 
void f() { 
    g(); 
} 

보다 더 나은 이유에

int main() 
{ 
    struct Local 
    { 
     static string Some() 
     { 
      return ""; 
     } 
    }; 
    std::cout << Local::Some() << std::endl; 
} 
+2

굉장한 언어 학대. – Joshua

+0

왜 '악용'입니까? (나는 진정으로 호기심이 많습니다.) – Samaursa

5

: 그것은 지역 수준의 기능을 남용 필요 가능하면 이름 충돌이 거의 발생하지 않도록 가능한 한 나는 로컬에서 함수를 선언하는 것이 (이 방법으로) 이 실제로 인 것은 논란의 여지가있다. 평범한 것보다 머리말을 포함시키는 것이 더 좋을 것이라고 생각하고 사람들에게 혼란스럽지 않은 "평범한"방법을 생각한다. . 때때로, 그것은 C에 숨겨진 된 기능 물론

void f() { 
    int g; 
    // oops, ::g is shadowed. But we can work around that 
    { 
     void g(); g(); 
    } 
} 

를 해결하는 것이 유용 ++ 우리가 its_namespace::g()를 사용하여 기능 g를 호출 할 수 있습니다 - 그 일이지만 불가능했을 것입니다 C의 옛날에, 그리고 프로그래머는 여전히 함수에 액세스 할 수있었습니다. 구문 론적으로는 같지 않지만 의미 상으로 다음은 또한 다른 범위를 실제로 대상으로하는 로컬 범위 내에서 함수를 선언한다는 점에 유의하십시오. 선언의 목표 범위 하지 그 선언에 표시되는 범위이다. 일반적으로 선언 기업이 범위의 구성원이 그런 쪽 참고로

int main() { 
    using std::exit; 
    exit(); 
} 

더 경우가 있습니다 선언이 나타납니다. 하지만 항상 그런 것은 아닙니다. 예를 들어 친구 그 일이

struct X { friend void f() { std::cout << "WoW"; } }; 
int main() { void f(); f(); } // works! 

심지어 함수 선언하지만 어떻게 선언에 대한 고려 (및 정의!) fX의 범위 내에서 무슨 일이 있었의 엔티티 (함수 자체가) 바깥 쪽 네임 스페이스의 일원이되었다 .

+0

좋은 설명. 많은 감사 litb –

+1

+1 그 마지막 '친구'- 이상한 - 그냥 친구를 신뢰할 수 없다;) – slashmais

+0

나는 '친구'트릭을 얻을하지 않습니다. 'X :: f()'를 둘러싼 네임 스페이스에 속하게합니까? – ofavre