C++은 강력한 객체 지향 프로그래밍(Object-Oriented Programming, OOP) 기능을 제공하는 언어입니다. OOP의 중심에는 '클래스'와 '객체'라는 개념이 있으며, 이를 정확히 이해하는 것이 효율적인 소프트웨어 설계의 시작입니다.
이번 포스팅에서는 C++ 클래스와 객체의 정의부터 생성자, 소멸자, 그리고 데이터를 보호하는 캡슐화까지 예제와 함께 자세히 알아보겠습니다.

1. 클래스(Class)란 무엇인가?
클래스(Class)는 객체를 만들기 위한 설계도(Blueprint) 또는 틀입니다. 클래스는 상태를 나타내는 데이터(멤버 변수)와 동작을 정의하는 함수(멤버 함수)로 구성됩니다.
클래스 정의 방법
C++에서 클래스는 class 키워드를 사용하여 정의하며, 마지막에 반드시 세미콜론(;)을 붙여야 합니다.
class Car {
public:
// 멤버 변수 (상태)
string model;
int speed;
// 멤버 함수 (동작)
void accelerate() {
speed += 10;
}
};
2. 접근 지정자 (Access Specifiers)
C++ 클래스는 외부에서 멤버에 접근할 수 있는 범위를 세 가지 접근 지정자로 제어합니다. 이는 보안과 유지보수 측면에서 매우 중요합니다.
- public: 어디서든 접근 가능. 클래스 외부 인터페이스로 사용됩니다.
- private: 클래스 내부 멤버 함수에서만 접근 가능. (기본 설정값)
- protected: 클래스 내부 및 상속받은 자식 클래스에서 접근 가능.
3. 객체(Object)란 무엇인가?
객체(Object)는 클래스라는 설계도를 바탕으로 메모리에 실제로 구현된 인스턴스(Instance)입니다. 설계도가 하나라면, 이를 통해 여러 개의 실제 객체를 찍어낼 수 있습니다.
객체 생성 및 사용
// 객체 생성
Car myCar;
// 멤버 접근 (점 연산자 '.' 사용)
myCar.model = "Sonata";
myCar.speed = 80;
myCar.accelerate();
4. 생성자와 소멸자 (Constructor & Destructor)
객체가 생성되고 사라질 때 자동으로 호출되는 특별한 함수입니다. 리소스를 할당하거나 해제할 때 필수적입니다.
생성자 (Constructor)
객체 생성 시 멤버 변수를 초기화합니다. 클래스 이름과 동일하며 반환 타입이 없습니다.
소멸자 (Destructor)
객체가 메모리에서 해제될 때 호출됩니다. 클래스 이름 앞에 ~를 붙이며, 메모리 누수를 방지하기 위한 정리 작업에 쓰입니다.
#include <iostream>
using namespace std;
class Robot {
public:
string name;
// 생성자: 객체 생성 시 이름 초기화
Robot(string n) : name(n) {
cout << name << " 로봇이 가동되었습니다." << endl;
}
// 소멸자: 객체 소멸 시 호출
~Robot() {
cout << name << " 로봇이 정지되었습니다." << endl;
}
};
int main() {
Robot myRobot("Alpha"); // 생성자 호출
return 0; // 메인 함수 종료 시 객체 소멸, 소멸자 호출
}
5. 캡슐화와 Getter/Setter
캡슐화(Encapsulation)는 데이터를 외부의 잘못된 접근으로부터 보호하고 관리하는 OOP의 핵심 원칙입니다. 멤버 변수는 private으로 숨기고, public 함수인 Getter와 Setter를 통해 데이터를 주고받습니다.
캡슐화 실전 예제
단순히 값을 넣는 것이 아니라, Setter 내부에서 데이터의 유효성 검사를 할 수 있다는 점이 핵심입니다.
#include <iostream>
#include <string>
using namespace std;
class Account {
private:
int balance; // 잔액은 외부에서 직접 수정 불가능하도록 은닉
public:
// Setter: 잘못된 값이 들어오지 못하게 제어
void setBalance(int money) {
if (money < 0) {
cout << "오류: 잔액은 0보다 작을 수 없습니다." << endl;
} else {
balance = money;
}
}
// Getter: 안전하게 값을 반환
int getBalance() {
return balance;
}
};
int main() {
Account myAcc;
myAcc.setBalance(10000); // 안전한 접근
myAcc.setBalance(-500); // 오류 메시지 출력
cout << "현재 잔액: " << myAcc.getBalance() << "원" << endl;
return 0;
}
결론: 왜 클래스를 사용해야 할까?
클래스와 객체를 사용하면 코드의 재사용성이 높아지고 유지보수가 쉬워집니다. 특히 규모가 큰 프로젝트나 임베디드 시스템 개발 시, 하드웨어 모듈을 클래스로 추상화하여 관리하면 훨씬 체계적인 프로그래밍이 가능합니다.
오늘 살펴본 캡슐화와 접근 지정자를 적절히 활용하여 더욱 안전하고 견고한 C++ 코드를 작성해 보세요!
'Core Programming > Modern C++ & System Design' 카테고리의 다른 글
| C++ 연산자 오버로딩 완벽 정리: 복소수 예제로 배우는 연산자 재정의 (0) | 2024.12.19 |
|---|---|
| C++ 상속과 다형성 완벽 가이드: 가상 함수와 추상 클래스 활용법 (0) | 2024.12.19 |
| C++ 동적 메모리 관리 완벽 가이드: new/delete부터 스마트 포인터까지 (0) | 2024.12.19 |
| C++ 포인터와 참조 완벽 정리: 차이점부터 메모리 구조, 활용법까지 (0) | 2024.12.18 |
| C++ 배열과 문자열 완벽 가이드: 메모리 구조부터 std::string 활용법까지 (0) | 2024.12.18 |