본문 바로가기

복습/C++

[C++] 복습일지 c++ 파일분할

안녕하세요


오늘은 C++ 파일분할법에 대해서 공부를 했습니다.


지금까지 저는 'main.cpp' 라는 파일 하나에 작성을 해왔습니다.


물론 틀린 방법은 아닙니다. 하지만 프로그램의 규모가 커지고, 코드의 줄도 길어진다면 가독성이 떨어지지않을까요?

또 다른곳에서 사용을 할 수도 있는 코드는 재사용성이 있으므로, 나누는것이 효율적이라는 생각이 듭니다.


'헤더파일'

'cpp파일'


이렇게 두 종류로 나눌 수 있는데요

header는 단어를 해석하자면, 머리 라는뜻이 있는데요


헤더파일 : 클래스의 선언부, 함수 선언  확장자는 .h

cpp파일 : 클래서의 구현부, 함수 구현 확장자는 .cpp


그렇다면 나누는 법을 알아보도록 하겠습니다.



#include <iostream>

class Calculator
{
public:
    ~Calculator(){}
    Calculator()
    {
        a = 0;
        b = 0;
        result = 0;
        std::cout << "계산기 생성" << std::endl;
    }
    void Add(int x, int y)
    {
        a = x;
        b = y;
        result = a + b;
    }
    void Subtract(int x, int y)
    {
        a = x;
        b = y;
        result = a - b;
    }
    void ShowResult()
    {
        std::cout << "result : " << result << std::endl;
    }
private:
    int a;
    int b;
    int result;
};
int main()
{
    Calculator c;
    c.Add(1, 2);
    c.ShowResult();
    c.Subtract(1, 2);
    c.ShowResult();
}


Calculator 클래스를 예를 들겠습니다.

굳이 저렇게 작성했습니다. 


여기서 헤더는 선언부입니다.

선언'만' 하는 부분입니다.


[함수의 선언]

~Calculator(){}

Calculator();

void Add(int x, int y);

void Subtract(int x, int y);

void ShowResult();


[변수의 선언]

int a;

int b;

int result; 



그렇다면 

헤더파일을 만들어 보겠습니다.



이름은 클래스명과 똑같이 하면 되겠습니다.


그러면 여기서 나오는 


#ifndef Calculator_h

#define Calculator_h


#endif


이 뜻이 궁금하실텐데요


if

define

 end... if 대충 짐작을 하자면

만약에 ~ 이런뜻인것 같습니다.


정확하게 짚고 넘어가겠습니다.


'#'의 문자열이 붙는다면 이것은 '전처리기' 입니다.


전 처리기의 용어를 보자면 '처리하기 전' 이라는 뜻인데

컴파일이 실행되기 전 명령문 입니다.




ifndef는  무엇인가?


if not defined Calculator_h                       Calculator_h가정의되어있지않다면

define  Calculator_h                                 를 정의한다.

endif                                                         여기까지


그러면 #define Calculator_h 아래에 코드를 삽입하면 되겠습니다.

이 구문들을 쓰는 이유는 헤더파일이 중복 선언되는걸 막기 위해서입니다.

헤더파일이 중복된다면 이중중복이 되어서 컴파일에러가 날게 분명합니다.


다른 방식은


#pragma once 

이후 코드삽입


입니다.

두 구문의 차이를 알아보겠습니다.



#ifndef

#define

#endif


  vs


#pragma once


위의 구문은 조건문을 통해 실행여부를 판단하고

아래의 구문은 '이 파일을 한번만 읽어들여라' 라는 뜻입니다.


pragma는 한번만 실행하기에 한번 실행 후에는 열어보지도 않습니다.


당연히 읽어들이기는 하는 #ifndef가 pragma보다 속도가 상대적으로 느린감이 있습니다.


결론은 pragma once 를 사용하는것이 효율적입니다.



다시 본론으로 오면 헤더파일은


Calculaotr.h



선언만 하면 됩니다!!


다음은 cpp입니다


Calculator.cpp


여기서 주의할점은 .cpp파일에


#include "Calculator.h"


를 작성해주셔서 머리를 조립해주시면 됩니다.

그리고 함수명 앞에 

클래스명과 scope연산자를 적어주시면됩니다


클래스명::함수명


범위연산자는 이 함수나 변수가 어디로부터 가져오는지 알려주는 역할을 합니다.


그러면 머리와 몸은 완성이 됐습니다.

하지만 코드를 보시면 굉장히 불편한

빨간줄이 그어져있습니다.

이유는 


'std'식별자가 정의되어있지 않다 라는 뜻인데요


우리는 기본적으로 main()을 만들면

자동적으로 

#include <iostream> 생성이 되었는데요


iostream 은 Input/Output Stream 입출력 c++ 표준 라이브러리 입니다.


cpp파일에 #include <iostream> 을 하면 될까요?

됩니다.

하지만 .cpp는 구현부입니다. 선언은 .h인 헤더파일에 하도록 하겠습니다.


헤더파일에 #include <iostream> 선언!


여기서 또하나의 의문이있습니다.

똑같은 #include 인데

어디서는<> 꺽쇄, 어디서는 "" 큰따옴표 인데요


꺽쇄 <> 를 쓰는 경우    :  꼭 그런것만은 아니지만 보통 컴파일러가 미리 만들어놓은 디렉토리안에서 헤더를 찾습니다. 기존 라이브러리같은경우.

큰따옴표 ""를 쓰는 경우 :  #include 를 한 파일과 동일한 디렉토리를 검색합니다.  주로 프로그래머가 직접 정의한 헤더파일을 include할 때 씁니다.



우리는 큰따옴표 ( "" )를 씁니다.



이렇게 완성이 되었습니다.

이제 이것을 main()에서 사용을 하려 한다면 

main()에 include 시키면 되겠습니다.



헤더파일만 포함을 시키면 .cpp는 따라옵니다.

main()코드가 한결 깔끔해졌습니다.





헤더파일은 연결시켜주는 '다리(Bridge)' 역할이라고 보시면됩니다.



Calculator.h

 - main()  함수호출

 - Calculator.cpp 함수구현

이렇게 이어진다고 보시면됩니다.


마지막으로 제가 파일 분할을 하다가 알게 된점입니다.

1. virtual (가상함수) 는 선언부에서 한번만 선언한다.

예를들어 

virtual void A()

{

foo

}

라는 함수가있다면


header : virtual void A();

.cpp : void A(){foo}


이렇게 virtual은 한번만 사용하시면 되겠습니다.


2. static은 헤더파일에 선언하고 구현한다.

예를들어


A.h 이라는 헤더파일에

class A

{

public:

static int GetX()

{

foo

}

}

이런식으로 선언과 구현을 동시에 하면 됩니다.



여기까지 파일분할이었습니다.


[알게된 점]

 - 파일분할시 virtual과 static의 사용법

 - 파일분할방법

 - 범위연산자

 - #pragma once와 #ifndef 의 차이


[부족한 점]

 - 세부적인 컴파일과정

 - 어셈블리언어를 배워야 할 것 같다. 배우고싶다.


잘못된점이나 지적 감사하겠습니다!