카테고리 없음

김민찬 5주차 수업 후 과제

content9349 2025. 10. 1. 14:37

 

 

1. 캡슐화

실생활 예: 스마트폰

  • 스마트폰 안에는 전화 걸기, 문자 보내기, 사진 찍기 같은 여러 기능이 다 들어있어.
  • 사용자는 복잡한 내부 구조를 몰라도 아이콘만 눌러서 쉽게 쓸 수 있지.
  • 즉, 데이터(사진, 연락처)와 기능(전화 걸기, 메시지 보내기)이 하나로 묶여 있는 거야.

2. 상속

실생활 예: 가족 유전자

  • 부모가 가진 키, 눈 색깔 같은 특징이 자식에게 물려지는 것과 같아.
  • 예를 들어, '동물'이라는 큰 집단에서 '강아지'와 '고양이'가 각각 부모(동물)에게서 공통 특성(숨 쉬기, 걷기)을 상속받는 거야.

3. 다형성

실생활 예: 리모컨 버튼 ‘전원’

  • TV 리모컨의 ‘전원’ 버튼은 TV를 켜고 끄지만, 에어컨 리모컨의 ‘전원’ 버튼은 에어컨을 켜고 꺼.
  • 같은 ‘전원’ 버튼이지만 기기에 따라 다르게 작동하는 것처럼 기능은 같아도 결과가 달라질 수 있어.

4. 추상화

실생활 예: 자동차 운전

  • 운전자는 엔진 구조나 연료 공급 방식을 몰라도 핸들과 페달로 자동차를 움직일 수 있어.
  • 복잡한 내부는 숨기고, 운전자가 꼭 알아야 할 부분만 보여주는 거야.

============================================================================================

 

  • Java
    • 기업용 서버, 안드로이드 앱, 웹 애플리케이션 등에서 광범위하게 사용됩니다.
  • Python
    • 쉽고 빠른 개발, 데이터 과학, 웹 개발, AI 분야에서 인기 많아요. OOP도 지원합니다.
  • C++
    • 성능이 중요한 게임, 시스템 프로그래밍, 임베디드 분야에서 많이 쓰입니다.
  • C#
    • 마이크로소프트 환경, 게임 개발(Unity), 데스크톱 및 웹 앱에 많이 활용돼요.
  • JavaScript (특히 ES6 이후)
    • 웹 프론트엔드와 백엔드(Node.js)에서 객체지향적 코드 작성이 늘고 있습니다.
  • Ruby
    • 웹 개발(Ruby on Rails) 중심으로 아직도 꽤 인기가 있어요.
  • Swift
    • iOS/macOS 앱 개발에 주로 쓰입니다.
  • Kotlin
    • Android 앱 개발에서 점점 Java를 대체하며 많이 쓰이고 있어요.

============================================================================================

 

 

 

 

 

 

 

1. 클래스 (Class)

  • 붕어빵 틀이라고 생각하면 돼. 붕어빵의 설계도이자 생김새를 정의한 것이야. 아직 실제 붕어빵은 아니야.

2. 객체 (Object)

  • 붕어빵 틀로 만들어질 수 있는 모든 붕어빵을 통틀어 부르는 말이야. 클래스(설계도)를 통해 만들어질 수 있는 대상을 말해.

3. 인스턴스 (Instance)

  • 지금 내 손에 있는, 특정 팥 붕어빵 하나처럼, 클래스(틀)를 통해 실제로 만들어져서 존재하는 구체적인 붕어빵 하나를 인스턴스라고 불러.

============================================================================================

 

 

 

클래스 만드는게 캡슐화이다.

캡슐화 (Encapsulation) = TV 리모컨!

당신이 TV를 본다고 생각해 보세요.

  1. TV 안의 복잡한 전선, 회로 (데이터)
    • TV 안에는 복잡한 부품들과 전선들이 잔뜩 있습니다. 이것은 TV가 어떻게 작동하는지 알려주는 '데이터' 같은 것입니다.
  2. 리모컨의 버튼들 (메서드/기능)
    • 하지만 당신은 TV의 복잡한 내부를 알 필요가 없습니다. 그냥 리모컨의 '전원' 버튼을 누르고, '채널' 버튼을 누르면 TV가 켜지고 채널이 바뀌죠.
  3. 캡슐화의 비밀!
    • 여기서 캡슐화 TV의 복잡한 내부 (데이터)는 숨겨 놓고, 당신이 조작할 수 있는 **간단한 리모컨 버튼들 (기능)**만 보여주는 것과 같습니다.

프로그래밍에서 캡슐화가 왜 중요하게 지켜지는지:

  • 오류 방지 (데이터 보호)
    • 만약 TV 내부의 전선을 당신이 직접 만질 수 있다면, 실수로 건드려서 고장 낼 수도 있겠죠? 캡슐화는 프로그램 속 중요한 '데이터'를 보호해서, 다른 코드들이 함부로 건드려 망가뜨리지 않도록 지켜줍니다. 프로그램이 엉망이 되는 것을 막아주는 것입니다.
  • 쉽게 고치고 업그레이드 (유지보수)
    • TV를 새로 만들 때 내부 부품이 바뀌더라도, 리모컨 버튼 기능만 똑같이 유지하면 당신이 다시 사용 방법을 배울 필요가 없겠죠? 캡슐화가 잘 되어 있으면, 프로그램의 '내부 작동 방식'이 바뀌어도, 그걸 사용하는 다른 부분들은 영향을 받지 않습니다. 덕분에 코드를 고치거나 새로운 기능을 추가하기가 훨씬 쉬워집니다.

그래서 개발자들은 보통 '데이터'는 외부에서 직접 접근하지 못하게 숨겨놓고, 그것을 다루는 '기능'들만 외부에 공개해서 사용하게 합니다. 이것은 프로그램을 만들 때 **"안전하고 유지보수하기 쉬운 코드를 만들자!"**는 약속과 같습니다.

 

어때요, 이제는 캡슐화가 왜 중요한지 쉽고 명확하게 이해가 되었을까요? 리모컨 덕분에 복잡한 TV 내부를 몰라도 잘 쓸 수 있는 것처럼, 캡슐화 덕분에 프로그램이 안전하고 편리하게 작동하는 것입니다.

 

============================================================================================

 

다형성 (Polymorphism) = '같은 명령, 다른 결과'

다형성은 말 그대로 **'여러 형태를 가질 수 있다'**는 의미입니다.

프로그래밍에서는 **'하나의 명령(메시지)에 대해, 여러 종류의 객체가 각자 다른 방식으로 동작하는 능력'**을 뜻합니다.

가장 쉬운 비유:

  • '운전하다'는 명령이 있다고 가정해 보세요.
  • 당신이 '자동차'에 대고 '운전해!'라고 하면, 자동차는 자동차 방식대로 움직일 것입니다.
  • 하지만 당신이 '오토바이'에 대고 '운전해!'라고 하면, 오토바이는 오토바이 방식대로 움직일 것입니다.

여기서 '운전해!'는 같은 명령이지만, '자동차'와 '오토바이'라는 서로 다른 대상은 그 명령에 대해 각자 다른 방식으로 반응합니다. 이것이 바로 다형성입니다.


왜 다형성을 사용할까요? (장점)

  • 유연성: 프로그램을 만들 때, 나중에 새로운 종류의 차량(예: 트럭)이 추가되어도 '운전해!'라는 명령은 그대로 쓸 수 있습니다. 코드를 크게 바꿀 필요가 없어집니다.
  • 확장성: 새로운 기능을 쉽게 추가하고, 기존 코드를 고치지 않아도 됩니다.
  • 간결함: 코드를 반복해서 쓰지 않고, 깔끔하게 정리할 수 있습니다.

다형성은 코드를 유연하고 효율적으로 만들어서, 프로그램을 관리하고 발전시키는 데 아주 큰 도움을 줍니다.

 

============================================================================================

강아지 클래스 만들기
시험에 나올 수 있음(아래 코드와 비교)
시험에 나올 수 있음

친구가 쓴 C++ 코드에서 에러가 나는 이유는 struct Man 안의 age라는 변수가 **private**으로 선언되어 있기 때문입니다.

private이라고 선언된 변수는 오직 그 Man이라는 구조체(또는 클래스) 안에서만 사용하도록 허락됩니다. 구조체 밖(예: main 함수)에서는 age에 직접 값을 넣거나 그 값을 읽어올 수 없어요. 그래서 main 함수에서 kim.age = 10; 또는 std::cout << kim.age;를 하려고 하면 컴파일러가 "아니, private으로 된 건 못 건드려!"라고 알려주면서 에러를 발생시키는 것입니다.

해결하려면, age 변수에 접근할 수 있는 public 함수(예: setAge()나 getAge())를 만들어서 그 함수를 통해서만 age 값을 조작해야 합니다. 이것이 객체 지향 프로그래밍의 핵심인 캡슐화를 지키는 좋은 방법이에요.

 

프로퍼티, 필드, 멤버변수 세가지는 같은 용어이다.

 

객체지향 언어별 '데이터'와 '조작' 용어 비교

언어데이터(특성/상태)를 나타내는 용어 (한국어)데이터(특성/상태)를 나타내는 용어 (영어)조작(행동/기능)을 나타내는 용어 (한국어)조작(행동/기능)을 나타내는 용어 (영어)

C++ 멤버 변수, 데이터 멤버, 속성 Member Variable, Data Member, Attribute 멤버 함수, 메서드 Member Function, Method
Java 필드, 멤버 변수, 속성 Field, Member Variable, Attribute 메서드 Method
Python 속성, 멤버 변수 Attribute, Member Variable 메서드 Method
C# 필드, 프로퍼티, 멤버 변수 Field, Property, Member Variable 메서드 Method

 

============================================================================================

 

디폴트 속성은 private다

객체지향 언어별 접근 제한자(Access Modifier) 비교

언어접근 제한자설명

C++ public 클래스 외부에서 아무런 제한 없이 접근 가능합니다.
  protected 해당 클래스 내부, 친구(friend) 함수/클래스, 그리고 이 클래스를 상속받은 파생 클래스 내부에서만 접근 가능합니다.
  private 해당 클래스 내부와 친구(friend) 함수/클래스에서만 접근 가능합니다. 외부에서는 접근이 완전히 차단됩니다. (기본 접근 지정자)
Java public 어떤 클래스에서든 접근 가능합니다. 
  protected 해당 클래스 내부, 같은 패키지(package) 내부, 그리고 다른 패키지에 있어도 이 클래스를 상속받은 자식 클래스에서 접근 가능합니다. 
  (default) 접근 제한자를 명시하지 않을 경우 적용되며, 같은 패키지 내의 클래스에서만 접근 가능합니다. 다른 패키지에서는 접근할 수 없습니다. (패키지-private)  
  private 해당 클래스 내부에서만 접근 가능하며, 외부에서는 완전히 차단됩니다. 
C# public 프로그램의 어느 위치에서든 접근 가능합니다.
  protected 해당 클래스 내부 및 이 클래스를 상속받은 파생 클래스 내부에서 접근 가능합니다.
  private 해당 클래스 내부에서만 접근 가능하며, 외부에서는 접근할 수 없습니다.
  internal 현재 어셈블리(Assembly) 내에서만 접근 가능합니다. 즉, 같은 프로젝트 파일 내에서만 접근 가능합니다.
  protected internal 현재 어셈블리 내 어디서든 접근 가능하며, 또는 다른 어셈블리라도 해당 클래스를 상속받은 클래스에서 접근 가능합니다.
  private protected 해당 클래스를 선언한 어셈블리 내의 파생 클래스에서만 접근 가능합니다. (C# 7.2부터)
Python (별도의 키워드 없음) Python은 엄격한 접근 제한자를 제공하지 않습니다. 모든 멤버는 기본적으로 public하게 취급됩니다. 대신 **약속(Convention)**을 통해 접근을 제한합니다.
  _변수명 (싱글 언더스코어) (약속된 protected) 클래스 외부에서 직접 접근하지 않도록 권장하는 의미입니다. 하지만 기술적으로 접근은 가능합니다.
  __변수명 (더블 언더스코어) (약속된 private) 이름 맹글링(Name Mangling)이라는 기법을 통해 클래스 외부에서 직접 접근하는 것을 어렵게 만듭니다. 하지만 완전히 불가능한 것은 아닙니다. 

 

한눈에 보는 핵심!

  • C++, Java, C# 같은 언어들은 public, protected, private과 같은 키워드를 사용하여 접근 범위를 명시적으로 제어해요. 이것이 바로 캡슐화를 구현하는 주된 방법이죠 .
  • 특히 Java는 접근 제한자를 명시하지 않을 경우 default (패키지-private) 접근 수준을 가진다는 점이 특징이에요 .
  • Python은 다른 언어들처럼 엄격한 접근 제한자가 없고, 변수명 앞에 _나 __를 붙이는 개발자 간의 **약속(컨벤션)**을 통해 접근을 제한해요.  이건 Python의 유연함을 보여주는 부분이기도 하죠!

 

 

 

 

 

#include <iostream> // (1) 'iostream'을 가져와서 화면에 글자를 보이게 합니다 (출력).
class Man {         // (2) 'Man'이라는 이름의 사람 '설계도'를 만듭니다.
private:            // (3) 여기에 있는 내용은 이 'Man' 설계도 안에서만 쓸 수 있습니다. (외부에서 못 만져요)
	int age;        // (4) 사람의 나이를 저장할 공간.
	double weight;  // (5) 사람의 몸무게를 저장할 공간.
public:             // (6) 여기에 있는 내용은 누구나 다 쓸 수 있습니다. (외부 공개)
	void cry() {    // (7) 사람이 우는 '기능'을 만듭니다.
		std::cout << "ㅠㅠㅠㅠ\n"; // (8) 울면 화면에 "ㅠㅠㅠㅠ"를 보여줍니다.
	}
	void smile() {  // (9) 사람이 웃는 '기능'을 만듭니다.
		std::cout << "ㅎㅎㅎㅎ\n"; // (10) 웃으면 화면에 "ㅎㅎㅎㅎ"를 보여줍니다.
	}
};
int main()          // (11) 프로그램이 시작되는 곳입니다.
{
	Man kim;        // (12) 'Man' 설계도를 가지고 'kim'이라는 실제 사람을 만듭니다.
	kim.cry();      // (13) 'kim'에게 '울어라!' 하고 명령합니다.
	kim.smile();    // (14) 'kim'에게 '웃어라!' 하고 명령합니다.
}

 

1. C# 버전

C#은 Microsoft에서 만든 객체지향 언어로, C++과 문법적으로 유사한 부분이 많아 비교적 쉽게 변환할 수 있어. 콘솔 출력 방식만 Console.WriteLine()으로 바꿔주면 된단다!

csharp

using System; // System 네임스페이스를 사용합니다. Console.WriteLine을 사용하기 위해 필요해요.

// 'Man'이라는 이름의 클래스를 정의합니다.
class Man
{
    // private 접근 제한자를 가진 멤버 변수들을 선언합니다.
    private int age;
    private double weight;

    // public 접근 제한자를 가진 메서드들을 정의합니다.
    public void Cry() // C#에서는 메서드 이름을 대문자로 시작하는 것이 일반적인 관례입니다.
    {
        Console.WriteLine("ㅠㅠㅠㅠ"); // C#에서 콘솔에 출력할 때 사용합니다.
    }

    public void Smile() // 메서드 이름 관례에 맞춰 Cry와 동일하게 대문자로 시작합니다.
    {
        Console.WriteLine("ㅎㅎㅎㅎ"); // C#에서 콘솔에 출력할 때 사용합니다.
    }
}

// 프로그램의 시작점인 Main 메서드를 포함하는 클래스입니다.
class Program
{
    static void Main(string[] args) // C# 프로그램의 시작점입니다.
    {
        Man kim = new Man(); // 'Man' 클래스의 새 인스턴스(객체) 'kim'을 생성합니다.
        kim.Cry();           // 'kim' 객체의 Cry() 메서드를 호출합니다.
        kim.Smile();         // 'kim' 객체의 Smile() 메서드를 호출합니다.
    }
}

2. Java 버전

Java도 C++과 비슷한 객체지향 언어야. C#과 마찬가지로 콘솔 출력 방식만 System.out.println()으로 바꿔주면 되고, 프로그램의 시작점인 main 메서드가 public static이라는 점에 유의하면 돼!

java

// 'Man'이라는 이름의 클래스를 정의합니다.
class Man {
    // private 접근 제한자를 가진 멤버 변수들을 선언합니다.
    private int age;
    private double weight;

    // public 접근 제한자를 가진 메서드들을 정의합니다.
    public void cry() { // Java에서는 메서드 이름을 소문자로 시작하는 것이 일반적인 관례입니다.
        System.out.println("ㅠㅠㅠㅠ"); // Java에서 콘솔에 출력할 때 사용합니다.
    }

    public void smile() { // 메서드 이름 관례에 맞춰 소문자로 시작합니다.
        System.out.println("ㅎㅎㅎㅎ"); // Java에서 콘솔에 출력할 때 사용합니다.
    }
}

// 프로그램의 시작점인 main 메서드를 포함하는 클래스입니다.
// Java 파일명은 보통 이 public static main 메서드를 포함하는 클래스명과 같아야 합니다 (예: Main.java).
public class Main {
    public static void main(String[] args) { // Java 프로그램의 시작점입니다.
        Man kim = new Man(); // 'Man' 클래스의 새 인스턴스(객체) 'kim'을 생성합니다. 'new' 키워드 사용.
        kim.cry();           // 'kim' 객체의 cry() 메서드를 호출합니다.
        kim.smile();         // 'kim' 객체의 smile() 메서드를 호출합니다.
    }
}

C++과 비교했을 때 주요 차이점:

  • 콘솔 출력:
    • C++: std::cout << "문자열\n";
    • C#: Console.WriteLine("문자열");
    • Java: System.out.println("문자열");
  • 객체 생성: C#과 Java는 객체 생성 시 new 키워드를 사용합니다 (Man kim = new Man();). C++에서는 new 없이도 객체를 만들 수 있죠 (Man kim;).
  • 시작점: C++은 int main(), C#은 static void Main(string[] args), Java는 public static void main(String[] args)를 프로그램의 시작점으로 사용합니다.
  • 메서드 이름 관례: C#은 메서드 이름을 Cry(), Smile()처럼 대문자로 시작하는 PascalCase를, Java는 cry(), smile()처럼 소문자로 시작하는 camelCase를 일반적으로 사용해요.