본문 바로가기

C++

c++ 9 (여러개의 헤더와 소스)

암묵적인 룰

일반적으로 많은 C++ 개발자는 헤더파일 한개와 소스파일 한개를 이용해 클래스를 정의하여 사용한다.

즉 한개의 클래스는 한개의 헤더파일과 한개의 소스파일을 갖게 된다.

이것은 언어에서 강제하는 사항은 아니지만 그렇게 하는 것이 미덕이다.

 

함수의 선언과 몸체를 분리할 필요가 있는 이유

animal.h

#include <cstring> // strcpy를 사용하기 위해서는 헤더파일 그 자체에 include되어 있어야한다.


class Animal {
public:
    int legs;
    char name[50];
    
    Animal(int legs, const char* name) {
        this->legs = legs;
        strcpy(this->name, name);
    }
    
    void printInfo() {
        printf("동물의 이름: %s, 동물의 다리: %d\n", name, legs);
    }
};

 

main_header.h

#define _CRT_SECURE_NO_WARNINGS


#include <cstdio>
#include <cstring>
#include <cmath>
#include <ctime>
#include <cstdlib>


int count = 0; // 종료조건
 
void hoo();
void goo();
void foo();

 

main.cpp

#include "main_header.h"
#include "animal.h"


int main() {
    foo();
    Animal* animal = new Animal(2, "닭");
    animal->printInfo();
    return 0;
}


void hoo() {
    printf("hoo()\n");
    count++;
    foo();
}


void goo() {
    printf("goo()\n");
    count++;
    hoo();
}


void foo(){ // 선언만 해준 상태
    if (count <= 10) {
        printf("foo()\n");
        goo();
        count++;
    }
    
}
/* header 파일에 foo(); 이런식으로 함수를 선언해주면
 몸체는 여기 있구나 하고 c++ 컴파일러가 연결해준다. 그거를 Linking이라 부른다.
 그래서 foo()에서 goo()를 불러도 몸체가 위에 있건 아래에 있건 상관없이 이미 선언 부분이 나와있어
 이 함수를 찾아갈 수 있게 된다.
 cpp파일을 기준으로 컴파일 하기 때문에 위쪽의 선언부에 함수의 선언이 있다면
 그 선언된 함수와 실체 몸체를 갖고 있는 함수를 연결해준다. 선언을 보고 몸체를 찾아가기
*/

 

 

클래스의 멤버함수 분리

클래스에서 멤버함수의 선언과 정의를 분리하기 위해서는

클래스에는 함수의 선언 부분만 남겨둔 이후에

소스파일에서 해당 클래스의 함수를 정의하면 된다.

다음과 같은 방법으로 소스파일에서 멤버함수를 정의할 수 있다.

 

클래스명::멤버함수명(파라미터) {  ...

 }

 

 

헤더파일의 중복 정의를 막기 위해 사용하는 매크로

: 클래스의 중복 정의를 막아주기 위해서 매크로 전처리기를 자동으로 삽입해준 것, 헤더를 두 번 include 하지 않는다

 

1.

#pragma once

 

2.

#ifndef __HOUSE_H__

#define __HOUSE_H__

#endif

 

house.h

#ifndef __HOUSE_H__
#define __HOUSE_H__


class Animal; // 이 클래스가 어디있는지 모르지만 어딘가에 있다, 이 클래스를 나중에 다른 cpp파일에서 몸체와 다른 헤더파일에서 선언을 찾을 수 있다.
//#include "animal.h" 대신 전방선언 가능


class House{
public:
    Animal* animal;
    
    //Animal 포인터를 할당하는 함수
    void setAnimal(Animal* a);
};


class Goo; // 이런식으로 클래스 전방선언을 하게 되면 Foo의 입장에서 Goo라는 녀석이 어딘가에 있긴있구나 라는 것을 위쪽을 통해 알 수 있다


class Foo {
public:
    Goo* g;
};


class Goo {
public:
    Foo* f;
};


#endif

 

house.cpp

#include "house.h"


void House::setAnimal(Animal* a) {
    this->animal = a;
}

 

animal.h

#ifndef __ANIMAL_H__
#define __ANIMAL_H__


class Animal {
public:
    int legs;
    char name[50];
    
    Animal(int legs, const char* name); // 선언만 있다.
    
    void printInfo();
};


#endif

 

animal.cpp

#include "main_header.h"
#include "animal.h"


Animal::Animal(int legs, const char* name) {
    this->legs = legs;
    strcpy(this->name, name);
}
// 생성자의 몸체가 animal.cpp에 만들어짐


void Animal::printInfo() {
    printf("동물의 이름: %s, 동물의 다리: %d\n", name, legs);
}
// 클래스 내부 함수의 선언과 몸체를 나눌 수가 있게 됨

 

person.h

#ifndef __PERSON_H__
#define __PERSON_H__


#include "animal.h"


class Person : Animal{
public:
    char regist_no[50];
    Person(const char* regist_no, const char* person_name);
    
    void printInfo();
};


#endif

 

person.cpp

#include "main_header.h"
#include "person.h"


Person::Person(const char* regist_no, const char* person_name):Animal(2, person_name){
    strcpy(this->regist_no, regist_no);
}


void Person:: printInfo() {
    printf("사람이름 : %s, 주민등록번호 : %s\n", name, regist_no);
}

 

main.cpp

#include "main_header.h"
#include "animal.h"
#include "person.h"


int main() {
    Animal* animal = new Animal(4, "소");
    animal->printInfo();
    
    Person* person = new Person("1234-5678", "김말똥");
    person->printInfo();
    return 0;
    
}

 

 

과제형 연습 프로그래밍

 

 

Header.h 에 있는 int displayData[GRID_HEIGHT][GRID_WIDTH] = { 0, };을

extern int displayData[GRID_HEIGHT][GRID_WIDTH]; 으로 바꾼다.

그리고 Source.cpp에

int displayData[GRID_HEIGHT][GRID_WIDTH] = { 0, }; 로 바꾼다.

 

함수만 선언과 몸통을 분리하고 각각의 클래스마다 각각의 헤더파일과 각각의 소스파일만 만들면 된다.

Display.h를 만들어 

#ifndef __DISPLAY_H__

#define __DISPLAY_H__

 

#include "Header.h"

 

사이에 Display 함수를 붙여넣기

#endif

 

GameEngine, Header.h도 똑같이 바꿔준다

 

그 후 Source.cpp에 #include "Display.h", #include "GameEngine.h"를 적어준다.

 

이 상태에서 Display.cpp 만들어 #include "Display.h" 한 후

Display.h 에는 함수를 선언만 해주고

Display.cpp 에서 함수 내용을 붙여 넣어준다.

void Display::draw() { 내용 붙여넣기 }

 

GameEngine.cpp도 만들어서 마찬가지로 함수만 찾아내어 복사 붙여넣기 하면 됨

init, next, canGoDown, isLineFilled, gameOverDecision, makeUserBlock, trans, rotate 등등 모든 함수

 

void next (float dt, char keyboardInput);

에 next가 초록줄이 그어지면 ctrl  .(온점) 을 누르고 엔터치면 자동으로 만들어준다. 그걸 저장하고 cpp로 가면 있다

 

TetrisHelper.h도..

TetrisHelper.h에 있는 KEY_EVENT_RECORD krec;를

TetrisHelper.cpp로 옮겨준다.