🧩 객체지향 프로그래밍이란?
- 프로그램을 현실 세계의 사물(객체)처럼 바라보고, 그 사물의 속성(데이터)과 행동(기능)을 코드로 표현하는 방식이에요.
- 예를 들어 자동차라는 객체를 생각해보면:
- 속성: 색상, 브랜드, 속도
- 기능: 가속하기, 브레이크 밟기, 경적 울리기
즉, 프로그램을 단순히 “명령어 나열”로 보는 게 아니라, 객체들의 집합과 상호작용으로 보는 거죠.
🔑 객체지향의 4가지 핵심 개념
- 캡슐화 (Encapsulation)
- 데이터와 기능을 하나로 묶어 관리
- 예: TV 내부 회로는 몰라도 리모컨 버튼만 누르면 작동
- 상속 (Inheritance)
- 기존 객체의 특성을 물려받아 확장
- 예: 자동차 클래스를 상속받아 전기차 클래스를 만들기
- 다형성 (Polymorphism)
- 같은 기능이라도 객체마다 다르게 동작
- 예: 달리기(run) → 사람은 두 발로, 자동차는 바퀴로
- 추상화 (Abstraction)
- 불필요한 디테일은 감추고 중요한 것만 표현
- 예: 운전할 때 엔진 구조는 몰라도 “엑셀 밟기”만 알면 됨
🌟 객체지향 프로그래밍의 장점
- 재사용성: 만든 객체를 다른 프로그램에서도 활용 가능
- 유지보수 용이: 특정 부분만 수정해도 전체 영향 최소화
- 확장성: 새로운 기능을 쉽게 추가 가능
- 현실 세계와 유사: 직관적이라 협업 시 이해하기 쉬움
💻 객체지향 언어 예시
- Java ☕: 기업용 시스템에서 많이 사용
- C++ 🎮: 게임 개발, 시스템 소프트웨어
- Python 🐍: 데이터 분석, 웹 개발
- C# 🖥: 마이크로소프트 생태계
👉 정리하자면, 객체지향 프로그래밍은 “현실 세계를 코드로 옮겨와 직관적이고 유지보수하기 좋은 프로그램을 만드는 방법”이에요.
📊 2025년 인기 객체지향 프로그래밍 언어 순위 (IEEE Spectrum 조사 기준)
순위언어특징
🥇 1위 | Python | 배우기 쉽고, AI·데이터 과학·웹 개발 등 다방면 활용 |
🥈 2위 | Java | 기업용 시스템, 안드로이드 앱 개발에 여전히 강세 |
🥉 3위 | C++ | 게임, 금융, 고성능 시스템에서 수요 증가 |
4위 | C# | 마이크로소프트 생태계, 게임(Unity) 개발에 강점 |
5위 | JavaScript | 웹 프론트엔드 필수 언어지만 최근 순위 하락 |
6위 | TypeScript | 대규모 웹 프로젝트에서 안정성 확보 |
7위 | Kotlin | 안드로이드 공식 언어, Java 대체로 성장 |
8위 | Swift | iOS·macOS 앱 개발에 최적화 |
9위 | Rust | 메모리 안전성·성능으로 시스템 프로그래밍에서 급부상 |
10위 | Go | 클라우드·서버 개발에서 인기 상승 |
🔎 해석 포인트
- Python은 여전히 1위, 특히 AI와 데이터 분석 덕분에 압도적 인기를 유지.
- Java는 기업 환경에서 여전히 강력한 수요.
- C++은 AI·게임·금융 시스템 등 고성능 분야에서 다시 주목받고 있음.
- Rust와 Go 같은 신흥 언어도 점점 객체지향적 요소를 도입하며 성장 중.
👉 정리하면, Python·Java·C++·C#이 여전히 객체지향 언어의 핵심 축을 이루고 있고, Kotlin·Swift·Rust 같은 언어들이 차세대 주자로 부상하고 있어요.
🏠 집을 짓는 것과 객체지향
- 객체 = 방
집은 여러 개의 방으로 이루어져 있죠. 각 방은 고유한 역할(침실, 주방, 욕실)을 가지고 있어요. - 속성 = 방의 특징
침실은 침대와 옷장이 있고, 주방은 냉장고와 가스레인지가 있어요. - 메서드(기능) = 방에서 할 수 있는 행동
침실에서는 "잠자기()", 주방에서는 "요리하기()" 같은 행동을 할 수 있죠. - 집 전체(프로그램)는 방(객체)들이 모여서 완성됩니다.
🚗 자동차와 객체지향
- 클래스 = 자동차 설계도
자동차를 만들기 위한 청사진. "자동차는 바퀴 4개, 핸들 1개, 엔진 1개를 가진다" 같은 정의. - 객체(인스턴스) = 실제 자동차
설계도를 바탕으로 만들어진 실제 차량. 예: 빨간색 소나타, 파란색 테슬라. - 상속 = 전기차
기존 자동차 설계도를 물려받아, 엔진 대신 배터리를 넣는 식으로 확장. - 다형성 = 달리기 방식
"달리기(run)"라는 같은 명령을 내려도, 내연기관차는 휘발유로, 전기차는 전기로 움직여요.
💳 은행 계좌와 객체지향
- 캡슐화: 계좌의 잔액은 외부에서 직접 볼 수 없고, 입금/출금 기능을 통해서만 접근 가능.
- 추상화: 고객은 "돈을 넣는다/뺀다"만 알면 되고, 은행 내부 시스템(데이터베이스)은 몰라도 돼요.
🌟 한 줄 정리
객체지향 프로그래밍은 “세상을 작은 부품(객체)으로 나누고, 그 부품들이 서로 협력해서 전체 시스템을 완성하는 방식”이에요.
마치 레고 블록처럼, 각 블록(객체)을 조립해서 원하는 구조물을 만드는 것과 같다고 할 수 있죠.
🎯 등장 배경 요약
1. 절차지향의 한계
- 초기 프로그래밍은 절차지향적이었어요. 즉, “순서대로 명령을 실행”하는 방식이었죠.
- 하지만 프로그램이 커질수록:
- 변수와 함수가 따로 놀고
- 코드가 재사용하기 어렵고
- 유지보수가 복잡해졌어요
예를 들어, 레시피대로 요리하는 건 쉽지만, 요리사가 수백 명이고 메뉴가 수천 개면? 관리가 불가능하죠.
2. 현실 세계를 코드로 표현하고 싶었다
- 사람들은 현실의 사물(예: 자동차, 사람, 은행 계좌)을 프로그램 안에서 표현하고 싶었어요.
- 그런데 단순한 데이터 구조(struct)로는 행동(기능)까지 표현하기 어려웠죠.
- 그래서 데이터 + 기능을 하나로 묶은 객체(Object)라는 개념이 등장했어요.
마치 “자동차”라는 객체가 있고, 그 안에 “속도”라는 데이터와 “가속하기()”라는 기능이 함께 들어있는 것처럼요.
3. 재사용성과 유지보수의 필요
- 객체는 독립적이고 재사용 가능하게 만들 수 있어요.
- 예를 들어, “강아지” 클래스를 만들면, 다양한 강아지 객체를 쉽게 생성할 수 있죠.
- 코드 수정도 객체 단위로 하면 되니, 전체 시스템에 영향을 주지 않고 유지보수가 쉬워져요.
4. 캡슐화와 추상화의 장점
- 객체는 내부 구조를 숨기고, 필요한 기능만 외부에 보여줘요.
- 마치 TV 내부 회로는 몰라도 리모컨으로 채널만 바꾸면 되는 것처럼요.
- 이 덕분에 복잡한 시스템을 단순하게 다룰 수 있게 되었어요.
🧠 한 줄 정리
객체지향은 “복잡한 현실을 더 잘 표현하고, 유지보수와 협업을 쉽게 하기 위해” 등장한 프로그래밍 패러다임이에요.
객체지향 언어(OOP, Object-Oriented Programming)의 주요 특징 4가지는 다음과 같아요 👍
- 추상화 (Abstraction)
- 불필요한 세부사항은 감추고, 중요한 특징만 드러내는 개념입니다.
- 예: 자동차라는 객체를 만들 때 엔진 내부의 복잡한 구조는 숨기고, 운전자가 필요한 시동, 가속, 브레이크 같은 기능만 노출합니다.
- 캡슐화 (Encapsulation)
- 데이터(속성)와 메서드(기능)를 하나의 객체 안에 묶어서 외부에서 직접 접근하지 못하도록 보호합니다.
- 접근 제한자(private, public, protected)를 활용해 정보 은닉(Information Hiding)을 실현합니다.
- 상속 (Inheritance)
- 기존 클래스(부모, 슈퍼클래스)의 속성과 기능을 새로운 클래스(자식, 서브클래스)가 물려받아 재사용할 수 있습니다.
- 코드의 재사용성을 높이고, 공통 기능을 관리하기 쉽게 합니다.
- 예: 동물 클래스를 상속받아 강아지, 고양이 클래스를 만듦.
- 다형성 (Polymorphism)
- 같은 이름의 메서드나 연산자가 상황에 따라 다르게 동작할 수 있는 성질입니다.
- 오버로딩(Overloading, 같은 이름의 메서드 여러 개 정의)과 오버라이딩(Overriding, 부모 메서드를 자식 클래스에서 재정의)이 대표적인 예입니다.
👉 정리하면: 추상화, 캡슐화, 상속, 다형성 이 객체지향 언어의 4대 특징이에요.
많은 분들이 “C++은 객체지향 언어다”라고 단순히 말하지만, 정작 C++을 만든 개발자 비야네 스트롭스트룹(Bjarne Stroustrup)은 조금 다른 뉘앙스로 설명해왔습니다.
🧑💻 스트롭스트룹의 입장
- 그는 C++을 “순수 객체지향 언어”라고 부르지 않았습니다.
- 이유는 C++이 다중 패러다임 언어(multi-paradigm language)이기 때문이에요.
- 절차지향(Procedural) 스타일도 가능
- 객체지향(Object-Oriented) 스타일도 가능
- 제네릭(Generic, 템플릿 기반) 프로그래밍도 가능
- 즉, 객체지향만 강제하는 언어(Java, Smalltalk 같은)와 달리, C++은 개발자가 필요에 따라 다양한 스타일을 섞어 쓸 수 있도록 설계되었죠.
📌 왜 “객체지향 언어가 아니다”라는 말이 나왔을까?
- C++은 C와의 호환성을 유지하면서 발전했기 때문에, 순수하게 객체지향만을 강제하지 않음.
- 예를 들어, C 스타일의 함수와 전역 변수만으로도 프로그램을 작성할 수 있어요.
- 그래서 일부 사람들은 “C++은 객체지향 언어가 아니라 객체지향을 지원하는 언어”라고 표현합니다.
- 실제로 스트롭스트룹도 “C++은 객체지향을 포함한 여러 패러다임을 지원하는 언어”라고 강조했어요.
✨ 정리
- C++ = 객체지향 언어(OOP Language)라고 불러도 틀리진 않음.
- 하지만 창시자는 “C++은 객체지향만을 위한 언어가 아니라, 여러 패러다임을 지원하는 언어”라고 설명했어요.
- 따라서 “C++은 객체지향 언어가 아니다”라는 말은 맥락상 ‘순수 객체지향 언어가 아니다’라는 의미로 이해하는 게 맞습니다.
위에 그림은 C언어 방식.
아래에 그림은 C++ 방식.
자료와 함수를 하나로 묶으면 객체가 되고 그 객체가 모이면 시스템/프로그램 이 되고 이 시스템/프로그램 들이 모이면 소프트웨어 생택계 가 됩니다.
🧩 객체가 모이면?
- 객체 → 클래스 기반의 인스턴스들
- 같은 설계도(클래스)로부터 여러 객체가 만들어져요.
- 예: 자동차 클래스 → 빨간 자동차, 파란 자동차, 전기 자동차 객체들.
- 여러 객체 → 시스템(프로그램)
- 객체들이 서로 메시지를 주고받으며 협력할 때, 하나의 프로그램이 완성돼요.
- 예: 은행 프로그램
- 고객 객체, 계좌 객체, ATM 객체가 서로 상호작용 → 은행 시스템 완성.
- 여러 시스템 → 소프트웨어 생태계
- 프로그램들이 모여 더 큰 서비스나 플랫폼을 형성해요.
- 예:
- 결제 시스템 + 배송 시스템 + 상품 관리 시스템 → 온라인 쇼핑몰
- 로그인 서비스 + 게시판 서비스 + 알림 서비스 → SNS 플랫폼
🔎 비유로 이해하기
- 객체 = 레고 블록 하나
(데이터와 기능이 합쳐진 작은 단위) - 객체들이 모임 = 레고 구조물
(집, 자동차, 비행기 같은 완성품) - 여러 구조물이 모임 = 레고 마을
(여러 프로그램이 모여 하나의 거대한 소프트웨어 생태계)
✨ 정리
- 자료 + 함수 = 객체
- 객체 + 객체 = 프로그램(시스템)
- 프로그램 + 프로그램 = 더 큰 소프트웨어 생태계
즉, 객체는 작은 단위지만, 모이고 협력하면서 현실 세계를 닮은 복잡한 시스템을 만들어내는 거예요.
🧩 클래스(Class)
- 정의: 객체를 만들기 위한 설계도
- 특징: 속성(변수)과 행동(메서드)을 정의
- 비유: 아파트 설계도, 자동차 도면
- 예시 (Java):
class Car { String color; void drive() { System.out.println("달린다!"); } }
🚗 객체(Object)
- 정의: 클래스를 기반으로 실제로 만들어진 실체
- 특징: 메모리에 존재하며, 클래스에서 정의한 속성과 기능을 가짐
- 비유: 설계도로 지어진 실제 아파트 한 채, 실제 도로 위의 자동차
- 예시:
Car myCar = new Car(); // myCar는 객체 myCar.color = "red"; myCar.drive();
🔎 인스턴스(Instance)
- 정의: 특정 클래스에서 생성된 객체를 지칭할 때 쓰는 용어
- 특징: “이 객체는 Car 클래스의 인스턴스다”처럼 소속을 강조할 때 사용
- 비유: “이 아파트는 삼성 아파트 설계도의 인스턴스다”
- 예시:
- myCar는 Car 클래스의 인스턴스
- 즉, 객체라는 일반 개념 안에서, 어떤 클래스에서 만들어졌는지를 명확히 할 때 “인스턴스”라고 부름
📊 차이 요약
구분클래스(Class)객체(Object)인스턴스(Instance)
의미 | 설계도, 틀 | 설계도로 만들어진 실체 | 특정 클래스에서 생성된 객체 |
존재 | 추상적 개념 | 메모리에 존재 | 객체의 소속을 강조하는 용어 |
비유 | 자동차 설계도 | 실제 자동차 | “이 자동차는 Car 설계도의 인스턴스” |
✨ 정리하면:
- 클래스는 설계도,
- 객체는 그 설계도로 만들어진 실체,
- 인스턴스는 “객체가 어떤 클래스에서 나왔는지”를 강조할 때 쓰는 말이에요.
🏠 집 비유로 이해하기
개념설명집 비유
클래스(Class) | 설계도, 즉 집을 짓기 위한 청사진 | “아파트 설계도” |
객체(Object) | 설계도를 바탕으로 실제로 만들어진 실체 | 실제로 지어진 아파트 한 채 |
인스턴스(Instance) | 특정 클래스에서 생성된 객체임을 강조할 때 쓰는 용어 | “이 아파트는 ‘아파트 설계도(Class)’로부터 만들어진 인스턴스다” |
🔎 차이의 핵심
- 객체는 그냥 “존재하는 실체”를 가리켜요.
→ “저기 보이는 집은 객체다.” - 인스턴스는 “그 객체가 어떤 클래스에서 나왔는지”를 강조할 때 쓰는 말이에요.
→ “저 집은 ‘아파트 설계도(Class)’의 인스턴스다.”
즉, 모든 인스턴스는 객체지만, 객체라는 말이 항상 인스턴스라는 의미를 강조하는 건 아니에요.
✨ 정리
- 객체(Object) = 현실에 존재하는 실체 (집 자체)
- 인스턴스(Instance) = 그 객체가 특정 클래스(설계도)에서 만들어졌음을 강조하는 표현 (집이 ‘아파트 설계도’에서 지어졌다는 사실)
🧩 다형성(Polymorphism)이란?
- 하나의 인터페이스(같은 이름의 메서드)로 여러 객체가 각기 다른 동작을 할 수 있는 성질.
- 즉, “같은 메시지를 보내도 객체에 따라 다르게 반응한다”는 개념이에요.
🔑 다형성의 종류
- 정적 다형성 (Static Polymorphism)
- 컴파일 시점에 어떤 메서드가 호출될지 결정됨
- 구현 방식: 메서드 오버로딩 (Method Overloading)
- 예: add(int a, int b) 와 add(double a, double b) → 같은 이름, 다른 매개변수
- 동적 다형성 (Dynamic Polymorphism)
- 실행 시점에 어떤 메서드가 호출될지 결정됨
- 구현 방식: 메서드 오버라이딩 (Method Overriding)
- 예: makeSound() → Dog는 “멍멍”, Cat은 “야옹”
🚗 예시 (C++ 코드)
#include <iostream>
using namespace std;
class Animal {
public:
virtual void makeSound() { cout << "동물이 소리를 냅니다." << endl; }
};
class Dog : public Animal {
public:
void makeSound() override { cout << "멍멍!" << endl; }
};
class Cat : public Animal {
public:
void makeSound() override { cout << "야옹!" << endl; }
};
int main() {
Animal* a1 = new Dog();
Animal* a2 = new Cat();
a1->makeSound(); // 멍멍!
a2->makeSound(); // 야옹!
delete a1;
delete a2;
}
👉 같은 makeSound() 호출이지만, 객체의 타입에 따라 다른 결과가 나오는 게 다형성이에요.
🌟 다형성의 장점
- 유연성: 새로운 객체를 추가해도 기존 코드 수정 최소화
- 재사용성: 같은 인터페이스로 다양한 객체를 다룰 수 있음
- 가독성: 코드가 더 직관적이고 깔끔해짐
- 확장성: 기능 추가가 쉬움
✨ 한 줄 정리
Polymorphism = “하나의 인터페이스, 여러 개의 구현”
즉, 같은 명령을 내려도 객체마다 다르게 반응하는 능력이에요.
C++에서 클래스(class) 안에서 “자료 은닉(Information Hiding)”을 할 때 핵심은 접근 지정자(access specifier)를 통해 멤버(변수·함수)의 가시성을 제어하는 거예요. 즉, 자료형 자체가 특별히 달라지는 게 아니라, 같은 자료형이라도 접근 권한을 어떻게 주느냐에 따라 은닉이 달라집니다.
🧩 클래스에서 자료 은닉을 위한 접근 지정자 종류
접근 지정자의미기본 적용 대상특징
private | 클래스 내부에서만 접근 가능 | 클래스 멤버 변수/함수 | 외부에서 직접 접근 불가 → 캡슐화의 핵심 |
protected | 클래스 내부 + 상속받은 자식 클래스에서 접근 가능 | 상속 관계 | 외부에서는 접근 불가, 상속 구조에서만 열어줌 |
public | 어디서든 접근 가능 | 인터페이스 역할 | 외부에서 사용할 수 있는 함수(메서드) 제공 |
🔎 예시 코드
#include <iostream>
using namespace std;
class BankAccount {
private: // 은닉된 데이터
int balance;
public: // 외부에 공개된 인터페이스
BankAccount(int money) : balance(money) {}
void deposit(int amount) { balance += amount; }
void withdraw(int amount) { if(balance >= amount) balance -= amount; }
int getBalance() { return balance; }
};
int main() {
BankAccount acc(1000);
acc.deposit(500);
cout << acc.getBalance() << endl; // 1500 출력
// acc.balance = 9999; // ❌ private라서 직접 접근 불가
}
👉 여기서 balance는 private으로 은닉되어 외부에서 직접 접근할 수 없고, deposit(), withdraw(), getBalance() 같은 public 메서드를 통해서만 다룰 수 있어요.
📌 정리
- C++ 클래스에서 자료 은닉은 자료형의 종류가 아니라 접근 지정자(private, protected, public)로 구분됨.
- 일반적으로 멤버 변수는 private, 멤버 함수(인터페이스)는 public으로 두어 캡슐화를 구현.
- 필요할 경우 protected를 사용해 상속 관계에서만 접근 허용.
각 언어마다 객체지향(Object-Oriented Programming, OOP)을 표현하는 방식과 용어가 조금씩 달라요. 같은 개념이라도 언어 철학과 문법에 따라 다르게 불리거나 구현됩니다. 정리해드릴게요.
🧩 언어별 객체지향 용어 비교
개념CC++JavaScriptJavaPython
클래스(Class) | 없음 (struct만 존재, 함수와 데이터 분리) | class 키워드로 정의 | ES6부터 class 문법 제공 (실제로는 prototype 기반) | class 키워드로 정의 (순수 OOP 지향) | class 키워드로 정의 |
객체(Object) | 구조체 변수(데이터 묶음) | 클래스 인스턴스 | 객체 리터럴 {} 또는 new Class() | 클래스 인스턴스 | 클래스 인스턴스, 모든 것이 객체 |
인스턴스(Instance) | 없음 (구조체 변수는 단순 데이터 묶음) | new로 생성된 객체 | new 키워드로 생성된 객체 | new로 생성된 객체 | 클래스 호출로 생성된 객체 |
상속(Inheritance) | 없음 | class Child : public Parent | extends 키워드 (ES6) 또는 prototype 체인 | extends 키워드 | 클래스 정의 시 괄호 안에 부모 클래스 지정 |
다형성(Polymorphism) | 함수 오버로딩 불가 | 함수 오버로딩, 가상 함수(virtual) | 동적 타이핑 기반, 오버라이딩 가능 | 오버로딩(제한적), 오버라이딩 지원 | 오버라이딩 지원, 오버로딩은 기본적으로 없음 |
캡슐화(Encapsulation) | 없음 (모든 멤버 public) | private, protected, public | 원래는 접근제어자 없음 → #(private 필드) 추가됨 | private은 없고, public, protected, default 접근제어자 | 접근제어자 없음, _name, __name 네이밍 컨벤션으로 은닉 |
추상화(Abstraction) | 없음 | 추상 클래스(순수 가상 함수) | 인터페이스 없음, duck typing | abstract class, interface | 추상 클래스(abc 모듈), duck typing |
🔎 핵심 차이 포인트
- C: 절차지향 언어. 객체지향 개념 자체가 없음. 구조체는 단순 데이터 묶음.
- C++: 다중 패러다임 언어. 절차지향 + 객체지향 + 제네릭 모두 지원.
- JavaScript: 원래는 프로토타입 기반 언어. ES6 이후 class 문법이 추가되었지만 내부적으로는 prototype 체인.
- Java: 순수 객체지향 언어에 가까움. 모든 코드가 클래스 안에 존재.
- Python: “모든 것이 객체”라는 철학. 접근제어자가 없고, 네이밍 규칙으로 은닉을 표현.
✨ 정리
- C는 객체지향 개념이 아예 없고,
- C++은 객체지향을 지원하지만 강제하지 않으며,
- JavaScript는 prototype 기반이지만 class 문법을 흉내내고,
- Java는 객체지향을 강하게 강제하는 언어,
- Python은 유연하게 객체지향을 지원하면서도 duck typing 철학을 강조합니다.
getter와 setter는 객체지향 프로그래밍에서 캡슐화(encapsulation)를 구현할 때 가장 기본적으로 쓰이는 메서드예요.
즉, 멤버 변수를 private으로 숨기고, 외부에서는 getter(읽기)와 setter(쓰기)를 통해서만 접근하게 만드는 방식입니다.
🧩 기본 개념
- getter: 멤버 변수의 값을 읽어오는 함수
- 보통 get변수명() 형태
- setter: 멤버 변수의 값을 설정하는 함수
- 보통 set변수명(값) 형태
🚗 예제 (C++)
#include <iostream>
#include <string>
using namespace std;
class Person {
private:
string name; // 외부에서 직접 접근 불가
int age;
public:
// setter (값 설정)
void setName(string n) {
name = n;
}
void setAge(int a) {
if (a >= 0) age = a; // 유효성 검사 가능
}
// getter (값 읽기)
string getName() {
return name;
}
int getAge() {
return age;
}
};
int main() {
Person p;
// setter 사용 → 값 설정
p.setName("홍길동");
p.setAge(25);
// getter 사용 → 값 읽기
cout << "이름: " << p.getName() << endl;
cout << "나이: " << p.getAge() << endl;
return 0;
}
📌 실행 결과
이름: 홍길동
나이: 25
🔎 왜 getter/setter를 쓰나?
- 데이터 은닉: 멤버 변수를 private으로 숨김
- 유효성 검사: setter 안에서 잘못된 값이 들어오는 걸 막을 수 있음
- 예: 나이가 음수면 무시
- 유연성: 내부 구현을 바꿔도 외부 코드는 그대로 유지 가능
✨ 정리하면:
- getter는 값을 안전하게 꺼내는 창구,
- setter는 값을 안전하게 넣는 창구예요.
- 이 두 가지를 통해 클래스 내부 데이터는 보호되고, 외부에서는 안전하게 접근할 수 있습니다.
각 언어마다 접근 지정자(access modifiers)의 종류와 기본 동작이 조금씩 다릅니다. 한눈에 비교할 수 있도록 표로 정리해드릴게요.
🧩 언어별 Access Modifiers 비교
언어접근 지정자설명기본 접근 수준
C++ | public | 어디서든 접근 가능 | class는 기본 private, struct는 기본 public |
protected | 같은 클래스 + 상속받은 자식 클래스에서 접근 가능 | ||
private | 같은 클래스 내부에서만 접근 가능 | ||
Java | public | 모든 패키지/클래스에서 접근 가능 | 클래스 멤버는 기본 default (package-private) |
protected | 같은 패키지 + 다른 패키지의 자식 클래스 접근 가능 | ||
default (package-private) | 접근 지정자 생략 시, 같은 패키지 내에서만 접근 가능 | ||
private | 같은 클래스 내부에서만 접근 가능 | ||
PHP | public | 어디서든 접근 가능 | 기본 public |
protected | 같은 클래스 + 상속받은 자식 클래스 접근 가능 | ||
private | 같은 클래스 내부에서만 접근 가능 | ||
C# | public | 어디서든 접근 가능 | 클래스 멤버는 기본 private |
protected | 같은 클래스 + 상속받은 자식 클래스 접근 가능 | ||
private | 같은 클래스 내부에서만 접근 가능 | ||
internal | 같은 어셈블리(프로젝트) 내에서만 접근 가능 | ||
protected internal | 같은 어셈블리 + 상속받은 자식 클래스 접근 가능 | ||
private protected | 같은 어셈블리 내에서 상속받은 자식 클래스만 접근 가능 (C# 7.2+) |
🔎 핵심 차이
- C++: class는 기본 private, struct는 기본 public
- Java: default(package-private)라는 독특한 접근 수준 존재
- PHP: 단순하게 public/protected/private만 지원
- C#: internal, protected internal, private protected 등 가장 세밀한 제어 가능
✨ 정리하면:
- C++/PHP는 단순한 3단계(public/protected/private)
- Java는 패키지 개념을 반영한 default가 추가
- C#은 어셈블리 개념까지 포함해 가장 다양한 접근 제어자를 제공
C++에서 private과 protected는 둘 다 캡슐화를 위한 접근 지정자지만, 실제 현업 코드나 교재 예제에서 더 많이 쓰이는 건 private입니다.
🧩 이유 정리
1. private이 기본값
- class에서 접근 지정자를 생략하면 자동으로 private이 됩니다.
- 따라서 특별히 상속을 고려하지 않는 한, 멤버 변수는 대부분 private으로 선언하는 게 관례예요.
2. 캡슐화 원칙
- 객체지향의 핵심은 데이터 은닉 → 멤버 변수는 외부에서 직접 접근하지 못하게 막고, getter/setter 같은 public 메서드를 통해서만 접근하도록 하는 게 일반적입니다.
- 이 목적에 가장 잘 맞는 게 private.
3. protected의 용도
- protected는 상속 관계에서 자식 클래스가 부모의 멤버에 접근할 수 있도록 열어줄 때 사용합니다.
- 하지만 실제로는 “멤버 변수까지 상속받은 클래스에서 직접 건드리게 하는 것”은 권장되지 않아요.
- 대신 부모 클래스의 public 메서드를 통해 간접적으로 다루는 게 더 안전한 설계입니다.
- 그래서 protected는 함수(메서드)를 상속 구조에서 재사용할 때 주로 쓰이고, 변수에는 잘 안 씁니다.
📌 정리
- 실무/교재에서 가장 많이 쓰이는 건 private
- 멤버 변수는 거의 항상 private
- 외부 접근은 public 메서드로 제한
- protected는 상속 구조에서만 제한적으로 사용
- 주로 “자식 클래스가 오버라이드할 수 있도록” 함수에 붙임
- 멤버 변수에는 잘 쓰지 않음
✨ 한 줄로 말하면:
👉 C++에서는 private이 기본이자 가장 많이 쓰이고, protected는 상속 상황에서만 가끔 등장하는 조연이에요.
#include <iostream>
#include <string>
using namespace std;
class Creature
{
protected: //protected는 '자식만' 접근 가능
virtual void type() {}
};
class Dog : Creature { //접근지정자가 없으면 자동으로 private으로 지정됨(기본이 private, strcut 는 반대임)
private: //private은 외부에서 접근 불가
int _age;
double _weight;
public: //public은 외부에서 접근 가능
Dog() : _age(), _weight() {}
~Dog() {}
void type() override { cout << "dogType\n"; }
void smile() { cout << "흐흐흐흐\n"; }
void cry() { cout << "ㅠㅠㅠㅠ\n"; }
void setAge(int age) { this->_age = age; }
int getAge() { return this->_age; }
void setWeight(double weight) { this->_weight = weight; }
double getWeight() { return this->_weight; }
};
int main() {
Dog* jackTheReaper = new Dog();
jackTheReaper->setAge(10);
jackTheReaper->setWeight(1.2);
jackTheReaper->type();
cout << jackTheReaper->getAge() << "\n" << jackTheReaper->getWeight() << "\n";
delete jackTheReaper;
return 0;
}
#include <iostream>
#include <string>
class Man {
private:
int _age;
double _weight;
public:
void smile() { std::cout << "ㅎㅎㅎ\n"; }
void cry() { std::cout << "ㅠㅠㅠ\n"; }
};
int main() {
Man seo;
seo.cry();
seo.smile();
return 0;
}
👍 올려주신 코드를 하나씩 분석해보고, 객체지향적으로 더 보강할 수 있는 부분을 알려드릴게요.
🧩 코드 분석
class Man {
private:
int _age;
double _weight;
public:
void smile() { std::cout << "ㅎㅎㅎ\n"; }
void cry() { std::cout << "ㅠㅠㅠ\n"; }
};
- 클래스 정의
- Man이라는 클래스를 정의.
- private 멤버: _age, _weight → 외부에서 직접 접근 불가.
- public 멤버 함수: smile(), cry() → 객체의 행동을 표현.
int main() {
Man seo;
seo.cry();
seo.smile();
return 0;
}
- 객체 생성
- Man seo; → 스택에 seo라는 객체 생성.
- 메서드 호출
- seo.cry(); → "ㅠㅠㅠ" 출력
- seo.smile(); → "ㅎㅎㅎ" 출력
✅ 현재 코드의 특징
- 장점
- 클래스 문법을 잘 사용했고, 객체 생성 및 메서드 호출이 정상 동작.
- private 멤버 변수를 선언해 캡슐화의 기본 구조를 갖춤.
- 아쉬운 점
- _age, _weight 멤버 변수를 선언했지만 사용하지 않음.
- 생성자/소멸자가 없음 → 객체 초기화가 불완전할 수 있음.
- getter/setter가 없어 외부에서 나이, 몸무게를 안전하게 다룰 수 없음.
🔧 개선할 수 있는 부분
1. 생성자(Constructor) 추가
객체 생성 시 나이와 몸무게를 초기화할 수 있도록 하면 좋아요.
Man(int age, double weight) : _age(age), _weight(weight) {}
2. Getter / Setter 추가
캡슐화 원칙에 따라 멤버 변수는 private으로 두고, 접근은 메서드로만.
void setAge(int age) { _age = age; }
int getAge() const { return _age; }
void setWeight(double weight) { _weight = weight; }
double getWeight() const { return _weight; }
3. 정보 출력 메서드
객체 상태를 확인할 수 있는 메서드 추가.
void showInfo() {
std::cout << "나이: " << _age << ", 몸무게: " << _weight << std::endl;
}
🚀 개선된 코드 예시
#include <iostream>
#include <string>
using namespace std;
class Man {
private:
int _age;
double _weight;
public:
// 생성자
Man(int age, double weight) : _age(age), _weight(weight) {}
~Man() {}
// 행동
void smile() { cout << "ㅎㅎㅎ\n"; }
void cry() { cout << "ㅠㅠㅠ\n"; }
// Getter / Setter
void setAge(int age) { _age = age; }
int getAge() const { return _age; }
void setWeight(double weight) { _weight = weight; }
double getWeight() const { return _weight; }
// 정보 출력
void showInfo() {
cout << "나이: " << _age << ", 몸무게: " << _weight << endl;
}
};
int main() {
Man seo(25, 70.5); // 생성자로 초기화
seo.cry();
seo.smile();
seo.showInfo();
return 0;
}
📌 정리
- 지금 코드도 잘 동작하지만, 객체지향적으로는 생성자, getter/setter, 정보 출력 메서드를 붙이면 더 완성도가 높아집니다.
- 이렇게 하면 Man 클래스가 단순히 행동만 하는 게 아니라, 상태(나이, 몸무게) + 행동(웃기, 울기)를 모두 가진 진짜 객체다운 클래스가 돼요.
'1학년 대학 수업 > C++ 프로그래밍' 카테고리의 다른 글
5주차 예습 과제 (0) | 2025.09.30 |
---|---|
4주차 수업 후 과제 (0) | 2025.09.25 |
4주차 예습 과제 (0) | 2025.09.22 |
3 주차 수업 요약 (1) | 2025.09.18 |
3주차 예습 과제 (0) | 2025.09.13 |