이 강의에서는 하나의 예제(Player 클래스)로 아래를 한 번에 연습합니다.
•
.h / .cpp 분리(선언/정의 분리)
•
생성자(Constructor): 기본/매개변수/복사 생성자
•
소멸자(Destructor)
•
헤더 가드(Header Guard)
1) 헤더(.h)와 소스(.cpp)를 왜 분리하나요?
프로그램 규모가 커질수록 모든 코드를 한 파일에 넣으면 읽기/수정/재사용이 어려워집니다.
•
헤더 파일(.h): “무엇을 제공하는지”를 적는 곳
◦
클래스 선언
◦
함수 원형(프로토타입)
◦
상수/타입 정의
•
소스 파일(.cpp): “어떻게 동작하는지”를 적는 곳
◦
함수 구현
◦
클래스 메서드 정의
2) 예제 프로젝트 구성(딱 1개 예제로 끝내기)
아래 3개 파일이 하나의 예제입니다.
•
player.h
•
player.cpp
•
main.cpp
3) player.h (선언부) — 헤더 가드 포함
#ifndef PLAYER_H
#define PLAYER_H
#include <iostream>
class Player
{
public:
// (1) 기본 생성자
Player();
// (2) 매개변수 생성자
Player(const char* name, int height);
// (3) 복사 생성자
Player(const Player& another);
// (4) 소멸자
~Player();
void Display();
private:
char mName[256];
int mHeight;
};
#endif
C++
복사
Header Guard 작동 원리
•
#ifndef PLAYER_H : PLAYER_H가 아직 정의되지 않았다면
•
#define PLAYER_H : 지금 정의해두고
•
헤더 내용을 포함
•
#endif : 조건부 컴파일 종료
이 구조 덕분에 같은 헤더가 여러 번 include 되더라도 중복 정의 오류를 막을 수 있습니다.
4) player.cpp (구현부) — 생성자/복사 생성자/소멸자 구현
#include "player.h"
#include <cstring>
// (1) 기본 생성자: 아무 값도 안 주고 만들면 이게 호출됨
Player::Player()
{
strcpy(mName, "나달");
mHeight = 183;
}
// (2) 매개변수 생성자: 이름/키를 받아서 초기화
Player::Player(const char* name, int height)
{
// 문자열 복사(직접 복사 버전)
int len = strlen(name);
for (int i = 0; i < len; i++)
mName[i] = name[i];
mName[len] = '\0';
mHeight = height;
}
// (3) 복사 생성자: 다른 Player로 새 Player를 만들 때 호출
Player::Player(const Player& another)
{
strcpy(mName, another.mName);
mHeight = another.mHeight;
std::cout << "복사 생성자 호출: " << mName << std::endl;
}
// (4) 소멸자: 객체 수명이 끝나면 자동 호출
Player::~Player()
{
std::cout << mName << " 객체가 소멸되었습니다." << std::endl;
}
void Player::Display()
{
std::cout << "선수의 이름: " << mName << std::endl;
std::cout << "선수의 키: " << mHeight << "cm" << std::endl;
}
C++
복사
5) main.cpp (테스트 코드) — 생성/복사/소멸 흐름 확인
#include "player.h"
int main()
{
std::cout << "=== 프로그램 시작 ===" << std::endl;
// 1) 매개변수 생성자
Player federer("페더러", 184);
federer.Display();
std::cout << std::endl;
// 2) 복사 생성자
Player nadal(federer);
nadal.Display();
std::cout << "=== 프로그램 종료 ===" << std::endl;
// 지역 객체는 생성 역순(LIFO)으로 소멸
return 0;
}
C++
복사
6) 생성자/복사 생성자/소멸자 핵심 정리
•
생성자(Constructor)
◦
객체가 만들어질 때 자동 호출
◦
클래스 이름과 동일
◦
반환 타입 없음
◦
오버로딩 가능(매개변수 다르면 여러 개 가능)
•
디폴트 생성자(Default Constructor)
◦
매개변수 없이 호출 가능한 생성자
◦
생성자를 하나도 안 만들면 컴파일러가 자동으로 만들기도 함
◦
하지만 “매개변수 생성자”를 하나라도 직접 만들면, 컴파일러가 디폴트 생성자를 자동으로 안 만들어주는 경우가 많아서 직접 정의하는 습관이 안전함
•
복사 생성자(Copy Constructor)
◦
다른 객체로 새 객체를 만들 때 호출
◦
형태: Player(const Player& another)
◦
호출 예: Player b(a);
•
소멸자(Destructor)
◦
객체 수명이 끝나면 자동 호출
◦
형태: ~Player()
◦
클래스당 1개만 존재
7) 자주 실수(체크)
•
Player nadal(); 는 객체 생성이 아니라 함수 선언으로 해석될 수 있음
◦
객체를 만들려면 Player nadal; 처럼 괄호를 빼는 습관
•
new[] 로 할당한 배열은 delete[] 로 해제
◦
(이 페이지에서는 동적 할당 예제는 다루지 않음)
