2010-02-17 2 views
0

저는 C++의 초보자입니다.하지만 다음과 같은 것을 발견했습니다.해당 함수를 다른 번역 단위에서 링크 할 경우 클래스의 멤버 함수를 정의 할 수없는 이유는 무엇입니까?

나는이 파일이있는 경우 :

myclass.hpp :

class myclass { 
public: 
    myclass(); 
    void barf(); 
}; 

mymain.cpp :

#include "myclass.hpp" 

int main() { 
    myclass m; 
    m.barf(); 
    return 0; 
} 

내가 MyClass에의이 구현 사용

myclassA합니다. cpp :

#include <iostream> 

using namespace std; 

class myclass { // or include myclass.hpp, it both works fine 
public: 
    myclass(); 
    void barf(); 
}; 

myclass::myclass() { } //empty 
void myclass::barf() { 
    cout << "barfing\n"; 
} 

모든 것이 정상입니다.

myclassB.cpp :

#include <iostream> 

using namespace std; 

class myclass { 
public: 
    myclass() { } 
    void barf() { 
    cout << "barfing\n"; 
    } 
}; 

내가 오류 나는 멤버가 클래스 정의 내에서 정의 된 것을 제외하고 완전히 동일 MyClass의의 구현을 사용하는 경우에, 나는 연결 오류가 발생합니다 :

$ g++ myclassB.cpp mymain.cpp 
/tmp/cc4DTnDl.o: In function `main': 
mymain.cpp:(.text+0xd): undefined reference to `myclass::myclass()' 
mymain.cpp:(.text+0x16): undefined reference to `myclass::barf()' 
collect2: ld returned 1 exit status 

분명히 myclassB.cpp에서 빌드 된 개체 파일은 멤버 함수를 내 보내지 않습니다. 이러한 구현이 모두 동일한 방식으로 작동하지 않는 이유는 무엇입니까? C++에서 클래스 정의 안에있는 멤버 정의가 전역 적으로 보이지는 않지만, 클래스 외부에 정의되어 있다면 멤버 규칙이란 규칙이 있습니까?

답변

2

템플릿 등의 고유 한 정의가 좀 더 복잡하고 미묘한 방식으로 표현되어 있습니다.이 규칙은 일반적으로 ODR이라고하는 하나의 정의 규칙이라고합니다. [1] 해당 언어가 다른 번역 단위로 표시되고 [2]이 (가) 과 동일한 경우에만 [1] 클래스, 템플릿, 또는 인라인 함수가 동일한 고유 정의의 예로 허용되며 [3] 해당 토큰의 의미는 두 번역 단위에서 모두 동일합니다. (유효) 예

: ODR 위반

// file1.c: 
struct S { int a ; char b ; }; 
void f(S* p){ } 
// file2.c: 
struct S { int a ; char b ; }; 
void f(S* p){ } 

예 : Jagannaths 응답 이외에

file1.c: 
struct S 1 { int a ; char b ; }; 
struct S 1 { int a ; char b ; }; // error: double definition 
This is an error because a struct may not be defined twice in a single 
translation unit. 

// file1.c: 
struct S 2 { int a ; char b ; }; 
// file2.c: 

struct S 2 { int a ; char b b ; }; // error. 
This is an error because S2 is used to name classes that differ in a member name. 

// file1.c: 
typedef int X ; 
struct S 3 { X a ; char b ; }; 
// file2.c: 
typedef char X ; 
struct S 3 { X a ; char b ; }; // error. 
Here the two definitions of S3 are  
token for token identical, but the example is an error because the 
meaning of the name X has sneakily been made to differ in the two files. 
+0

나에게 그의 질문은 실제로 한 번만 클래스를 정의하는 것처럼 들렸지 만 그 정의는 소스 파일 내에서 두 번째 클래스 선언 안에있었습니다. – smerlin

+0

그는 myclass.hpp를 mymain.cpp에 포함시킨 다음 g ++ myclassB.cpp mymain.cpp을 사용하여 컴파일하려고했습니다. – Jagannath

1

인라인으로 정의 된 멤버 함수는 컴파일러에서 인라인 할 후보입니다. 그것이 결코 사용되지 않고 소스 파일의 내부에서만 정의 된 것이라면, 나는 당신의 컴파일러가이 방법을 모두 제거하고 있다고 의심한다.

즉, 헤더 파일에 선언을 넣고 .cpp 파일에 정의를 넣는 것이 좋습니다. 헤더 파일을 포함 시키십시오 (예 : #pragma once 또는 #idfef/#define 가드와 같은 적절한 가드 포함). 프로젝트가 커질수록이 작업을 수행해야합니다. 따라서 적절한 관행을 지금 작성하는 것이 가장 좋습니다.

0

는, I는 선언으로 계산 myclass.hpp에서 MyClass의 정의를 생각 하지만 C++에서는 정의이기 때문에 Jagannaths 대답이 적용됩니다.클래스를 선언 할 수는 있지만 그 클래스에 대한 포인터 나 참조 만 사용할 수는 있지만 멤버에 액세스 할 수는 없습니다. 참조 : Declare a C++ class without defining it in the current translation unit

관련 문제