선언과 정의의 분리&전방 선언

Jaemyeong Lee·2024년 8월 11일
0

FastCampusC++

목록 보기
55/78

제목: C++에서 선언과 정의의 분리 및 전방 선언의 중요성

C++에서 코드를 작성할 때, 클래스와 함수의 선언과 정의를 분리하는 것이 좋은 관례로 여겨집니다. 이 글에서는 선언과 정의의 분리 및 전방 선언을 이용한 코드 최적화와 유지보수성을 높이는 방법에 대해 살펴보겠습니다. 주어진 예제 코드를 통해 이를 자세히 분석해보겠습니다.

1. 선언과 정의의 차이

선언은 컴파일러에게 함수 또는 클래스의 존재를 알려주는 작업입니다. 반면, 정의는 함수 또는 클래스의 실제 내용을 구현하는 것입니다. 선언과 정의를 분리하면 코드의 가독성을 높이고, 컴파일 속도를 개선하며, 유지보수성을 높이는 장점이 있습니다.

function.h

#pragma once

#include <iostream>

using namespace std;

// 함수 선언, 정의가 포함되지 않은 선언
void func();

// 함수 정의, 선언이지만 정의가 포함
void func()
{
    cout << "func" << endl;
}

// 한 번 더 정의 하게 되면 중복 정의(컴파일이 안 됨)
//void func()
//{
//    cout << "func" << endl;
//}

이 코드는 func 함수의 선언과 정의를 포함하고 있습니다. void func();는 선언만을, 이후의 void func() { ... }는 정의를 포함한 선언입니다. 주석으로 설명된 것처럼, 함수는 동일한 파일에서 중복 정의될 수 없습니다. 이는 컴파일 오류를 유발합니다.

2. 클래스 선언과 정의의 분리

클래스의 선언과 정의를 분리하면 여러 파일에서 동일 클래스를 사용할 수 있으며, 이러한 구조는 코드의 재사용성을 높입니다.

person.h

#pragma once

#include <iostream>
#include <string>

// Person 클래스의 선언 분리
class Person
{
private:
    float _weight;
    float _height;
    const std::string _name;

public:
    Person(float weight, float height, const std::string& name);
    void print();
};

// 함수의 선언
void foo();

여기서는 Person 클래스와 foo 함수의 선언만 포함하고 있습니다. 클래스 내부의 변수와 메서드가 어떻게 정의될지 명시만 했을 뿐, 실제 구현은 포함되지 않았습니다.

person.cpp

#include "person.h"

// Person 클래스 함수들의 정의 분리
Person::Person(float weight, float height, const std::string& name)
    : _weight(_weight), _height(height), _name(name)
{
}

void Person::print()
{
    using namespace std;
    cout << _name << endl;
}

// 함수의 정의 분리
void foo()
{
    Person p(60.f, 160.f, "david");
    p.print();
}

Person 클래스와 foo 함수의 실제 구현이 포함된 파일입니다. 정의가 분리되어 있으므로, person.h 파일을 포함하는 다른 파일들은 person.cpp를 링크하여 컴파일합니다. 이렇게 함으로써 코드의 중복과 비효율성을 방지할 수 있습니다.

3. 전방 선언 (Forward Declaration)

전방 선언은 클래스의 정의를 미리 알려주는 방법입니다. 전방 선언을 통해 헤더 파일을 최소화할 수 있으며, 컴파일 시간을 단축할 수 있습니다.

Villiage.h

#pragma once

#include <vector>

// 전방 선언
class Person;

class Villiage
{
private:
    std::vector<Person*> persons;
public:
    void add(Person* person);
};

여기서 Villiage 클래스는 Person 클래스를 직접 포함하지 않고, 대신 전방 선언을 사용합니다. 이는 Person 클래스를 실제로 사용할 때만 포함하여 불필요한 의존성을 줄이고, 컴파일 시간을 단축시키는 효과를 줍니다.

Villiage.cpp

#include "Villiage.h"
#include "person.h"

void Villiage::add(Person* person)
{
    // 실제 person 객체에 대한 작업 수행
}

전방 선언된 Person 클래스는 실제로 이곳에서 포함되어 사용됩니다. 이를 통해 Villiage.h를 포함하는 다른 파일들이 불필요하게 person.h를 포함하지 않게 되어, 컴파일 속도가 빨라지고 의존성이 줄어듭니다.

4. main.cpp 파일

마지막으로, 모든 선언과 정의를 종합하여 사용하는 파일입니다.

#include <iostream>
#include "function.h"
#include "Villiage.h"
#include "person.h"

using namespace std;

void foo1(); // util1.cpp

int main()
{
    func();
    foo1();

    Villiage v;
    v.add(new Person(10, 10, "david"));
}

main.cpp 파일에서는 선언과 정의가 분리된 여러 함수와 클래스를 호출합니다. Villiage 클래스는 전방 선언된 Person 클래스의 포인터를 활용해 객체를 관리하며, Person 객체를 동적으로 생성하여 add 함수에 전달합니다.

결론

C++에서의 선언과 정의의 분리, 전방 선언은 코드의 가독성, 유지보수성, 컴파일 효율성을 높이는 중요한 방법입니다. 선언을 분리하여 인터페이스와 구현을 나누고, 전방 선언을 통해 의존성을 최소화함으로써 더 효율적인 코드를 작성할 수 있습니다. 이를 통해 팀 내 협업이나 프로젝트 규모가 커질 때 발생할 수 있는 문제들을 미리 방지할 수 있습니다.

profile
李家네_공부방

0개의 댓글