클래스 내부 또는 외부의 함수 선언


91

저는 C ++을 배우려는 JAVA 개발자이지만 표준 함수 선언에 대한 모범 사례가 무엇인지 실제로는 모릅니다.

수업에서 :

class Clazz
{
 public:
    void Fun1()
    {
        //do something
    }
}

또는 외부 :

class Clazz
{
public:
    void Fun1();
}

Clazz::Fun1(){
    // Do something
}

두 번째는 가독성이 떨어질 수 있다고 느낍니다 ...


1
여기에는 실제로 3 가지 옵션이 있습니다. 두 번째 예제는 헤더 파일 (여전히 인라인되지 않음) 또는 별도의 .cpp파일에 함수 정의를 포함 할 수 있습니다 .
Cody Gray

이 질문 은 이해하는 데 도움 될 수 있습니다.
Björn Pollex

3
참고 : 선언 은 항상 클래스 내부에 있지만 정의 는 내부 또는 외부에 있습니다. 질문 제목과 본문은 s / 선언 / 정의 / 믿어지지 않습니까? stackoverflow.com/q/1410563/1143274
Evgeni Sergeev 2015

1
클래스 내부의 함수 정의는 피해야합니다. 묵시적으로 간주 inline됩니다.
John Strood

@JohnStrood 그래서? inline다른 번역 단위가 사용하는 경우 필요한 하나의 정의 규칙 만 완화합니다Clazz
Caleth

답변:


57

C ++는 소프트웨어 개발을위한 객체 지향 패러다임을 지원한다는 점에서 객체 지향입니다.

그러나 Java와 달리 C ++는 클래스에서 함수 정의를 그룹화하도록 강요하지 않습니다. 함수를 선언하는 표준 C ++ 방식은 클래스없이 함수를 선언하는 것입니다.

대신 메서드 선언 / 정의에 대해 이야기하는 경우 표준 방법은 선언 만 포함 파일 (일반적으로 .h또는 .hpp)에, 정의를 별도의 구현 파일 (일반적으로 .cpp또는 .cxx) 에 넣는 것입니다 . 나는 이것이 실제로 다소 성 가시고 일부 중복이 필요하다는 데 동의하지만 언어가 설계된 방식입니다.

빠른 실험과 단일 파일 프로젝트의 경우 모든 것이 작동하지만 더 큰 프로젝트의 경우 이러한 분리가 실제로 필요한 것입니다.

참고 : Java를 알고 있더라도 C ++는 완전히 다른 언어이며 실험으로 배울 수없는 언어입니다. 그 이유는 비대칭이 많고 비논리적 인 선택이있는 다소 복잡한 언어이기 때문이며, 가장 중요한 것은 실수를 할 때 Java에서 좋아하는 "런타임 오류 천사"가 없다는 것입니다.하지만 대신 " 정의되지 않은 동작 데몬 ".

C ++를 배우는 합리적인 유일한 방법은 읽는 것입니다 ... 아무리 똑똑하더라도위원회가 결정한 내용을 추측 할 수있는 방법이 없습니다 (정답이 비논리적이고 역사적 결과이기 때문에 실제로 똑똑하다는 것은 때때로 문제가되기도합니다. 세습 재산.)

좋은 책 한두 권을 골라 전체적으로 읽으십시오.


7
누군가 Java에서 왔고 C ++에 대한 도움을 요청한다면 "당신이 아는 언어가 무언가에 집착하고있다"고 말하면 그에게 무엇을 말합니까? 그는 다른 언어와 비교할 수 없기 때문에 거의 아무것도 알려주지 않습니다. OP에 많은 것을 알려주지 않는 obsessed와 같이 감정적으로 내포 된 stronly 단어를 사용하는 것보다이 부분을 제외하는 것이 좋습니다. 또한 "모든 것에 클래스 사용"의 맥락은 무엇입니까? Java에서는 메서드에 클래스를 사용하지 않습니다. 변수에 클래스를 사용하지 않습니다. 파일에 클래스를 사용하지 않습니다. 여기서 "모든 것"은 무엇입니까? Ranting?
Daniel S.

3
@DanielS : 분명히 당신을 불쾌하게했기 때문에 그 부분을 제거했습니다. 실제로 Java를 전혀 사용하지 않기 때문에 Java에 대해 외치는 것이 아닙니다. 당시에는 OOP as Object Obsessed Programming이 우스운 농담이라고 생각했지만 분명히 그렇지 않았습니다. 저는 Java 1.1 인증 프로그래머 였지만 그 당시에는 어떤 이유에서든 강제로 "프로그래밍 언어"를 사용하지 않기로 결정했고 지금까지 피하는 데 성공했습니다.
6502

감사합니다. 이제 훨씬 더 잘 읽는 것 같습니다. 불쾌하게 들리면 죄송합니다. 다음에 좀 더 긍정적이되도록 노력하겠습니다.
Daniel S.

15
질문에 대답하지 않는다
페트르 펠러

1
@PetrPeller : 세 번째 단락에서 명확하지 않은 부분은 무엇입니까?
6502

27

첫 번째는 멤버 함수를 인라인 함수 로 정의 하고 두 번째는 그렇지 않습니다. 이 경우 함수의 정의는 헤더 자체에 있습니다.

두 번째 구현은 cpp 파일에 함수 정의를 배치합니다.

둘 다 의미가 다르며 스타일의 문제가 아닙니다.


2
cplusplus.com/doc/tutorial/classes 는 동일한 대답을 제공합니다. "클래스 멤버 함수를 클래스 내에 완전히 정의하거나 프로토 타입 만 포함하고 나중에 정의하는 것 사이의 유일한 차이점은 첫 번째 경우 함수가 자동으로 컴파일러에 의해 인라인 멤버 함수로 간주되는 반면 두 번째에서는 정상적인 (인라인이 아닌) 클래스 멤버 함수이며 실제로 동작에 차이가 없다고 가정합니다. "
Buttons840 2013

18

함수 정의는 클래스 외부에서 더 좋습니다. 이렇게하면 필요한 경우 코드를 안전하게 유지할 수 있습니다. 헤더 파일은 선언 만 제공해야합니다.

누군가가 당신의 코드를 사용하고 싶어한다고 가정하면, 당신은 그에게 당신의 클래스의 .h 파일과 .obj 파일 (컴파일 후에 얻은)을 줄 수 있습니다. 코드를 사용하기 위해 .cpp 파일이 필요하지 않습니다.

이렇게하면 구현이 다른 사람에게 표시되지 않습니다.


10

"Inside the class"(I) 메서드는 "outside the class"(O) 메서드와 동일합니다.

그러나 (I)는 클래스가 하나의 파일 (.cpp 파일 내부)에서만 사용되는 경우 사용할 수 있습니다. (O)는 헤더 파일에있을 때 사용됩니다. cpp 파일은 항상 컴파일됩니다. #include "header.h"를 사용하면 헤더 파일이 컴파일됩니다.

헤더 파일에서 (I)를 사용하면 #include "header.h"를 포함 할 때마다 (Fun1) 함수가 선언됩니다. 이로 인해 동일한 함수를 여러 번 선언 할 수 있습니다. 이것은 컴파일하기가 더 어렵고 오류가 발생할 수도 있습니다.

올바른 사용법의 예 :

File1 : "Clazz.h"

//This file sets up the class with a prototype body. 

class Clazz
{
public:
    void Fun1();//This is a Fun1 Prototype. 
};

File2 : "Clazz.cpp"

#include "Clazz.h" 
//this file gives Fun1() (prototyped in the header) a body once.

void Clazz::Fun1()
{
    //Do stuff...
}

File3 : "UseClazz.cpp"

#include "Clazz.h" 
//This file uses Fun1() but does not care where Fun1 was given a body. 

class MyClazz;
MyClazz.Fun1();//This does Fun1, as prototyped in the header.

File4 : "AlsoUseClazz.cpp"

#include "Clazz.h" 
//This file uses Fun1() but does not care where Fun1 was given a body. 

class MyClazz2;
MyClazz2.Fun1();//This does Fun1, as prototyped in the header. 

File5 : "DoNotUseClazzHeader.cpp"

//here we do not include Clazz.h. So this is another scope. 
class Clazz
{
public:
    void Fun1()
    {
         //Do something else...
    }
};

class MyClazz; //this is a totally different thing. 
MyClazz.Fun1(); //this does something else. 

당신은 의미 Clazz MyClazzClazz MyClazz2?
Chupo_cro

4

멤버 함수는 클래스 정의 내에서 정의하거나 범위 확인 연산자 ::를 사용하여 별도로 정의 할 수 있습니다. 클래스 정의 내에서 멤버 함수를 정의하면 인라인 지정자를 사용하지 않더라도 함수가 인라인으로 선언됩니다. 따라서 아래와 같이 Volume () 함수를 정의 할 수 있습니다.

class Box
{
  public:

     double length;
     double breadth;    
     double height;     

     double getVolume(void)
     {
        return length * breadth * height;
     }
};

원하는 경우 범위 확인 연산자를 사용하여 클래스 외부에서 동일한 함수를 정의 할 수 있습니다. :: 다음과 같이

double Box::getVolume(void)
{
   return length * breadth * height;
}

여기서 중요한 점은 :: 연산자 바로 앞에 클래스 이름을 사용해야한다는 것입니다. 멤버 함수는 다음과 같이 해당 개체와 관련된 데이터를 조작하는 개체에 대해 점 연산자 (.)를 사용하여 호출됩니다.

Box myBox;           

myBox.getVolume();  

( 출처 : http://www.tutorialspoint.com/cplusplus/cpp_class_member_functions.htm ) 두 가지 방법 모두 합법적입니다.

저는 전문가는 아니지만 하나의 파일에 하나의 클래스 정의 만 넣으면 실제로 중요하지 않다고 생각합니다.

그러나 내부 클래스와 같은 것을 적용하거나 여러 클래스 정의가있는 경우 두 번째 클래스는 읽고 유지 관리하기가 어렵습니다.


1
해당 링크의 관련 콘텐츠를 게시물 본문으로 가져 와서 죽은 링크에 대해 미래를 대비할 수 있습니까? 감사합니다
JustinJDavies 2014 년

2

첫 번째 파일은 헤더 파일 (클래스 선언이있는 곳)에 넣어야합니다. 두 번째는 헤더 또는 일반적으로 소스 파일의 모든 위치에있을 수 있습니다. 실제로는 클래스 선언에 작은 함수를 넣을 수 있습니다 (암시 적으로 인라인으로 선언하지만 궁극적으로 인라인 여부를 결정하는 것은 컴파일러 임). 그러나 대부분의 함수에는 두 번째 예제와 같이 헤더에 선언이 있고 cpp 파일에 구현이 있습니다. 그리고 아니요, 왜 이것이 덜 읽기 쉬운 지 모르겠습니다. 실제로 유형에 대한 구현을 여러 cpp 파일로 나눌 수 있다는 것은 말할 것도 없습니다.


1

클래스 내부에 정의 된 함수는 기본적으로 인라인 함수로 처리됩니다. 외부에서 함수를 정의해야하는 간단한 이유 :

클래스의 생성자는 가상 함수를 확인하고 적절한 VTABLE 또는 가상 메서드 테이블 을 가리 키도록 가상 포인터를 초기화 하고 기본 클래스 생성자를 호출하고 현재 클래스의 변수를 초기화하므로 실제로 일부 작업을 수행합니다.

인라인 함수는 함수가 그렇게 복잡하지 않고 함수 호출의 오버 헤드를 피할 때 사용됩니다. (오버 헤드에는 하드웨어 수준의 점프 및 분기가 포함됩니다.) 위에서 설명한 것처럼 생성자는 인라인으로 간주하기가 쉽지 않습니다.


"인라인"은 인라인과 거의 관련이 없습니다. 인라인으로 정의 된 멤버 함수가 암시 적으로 인라인으로 선언된다는 사실은 ODR 위반을 방지하기위한 것입니다.
Big Temp

0

인라인 함수 (클래스에서 선언 할 때 함수)를 호출 할 때마다 기본 메모리 코드에 붙여 넣습니다. 클래스 외부에서 함수를 선언 할 때 함수를 호출하면 동일한 메모리에서 가져옵니다. 그것이 훨씬 더 좋은 이유입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.