24.01.03 TIL - [C#] 기초 (8) : 클래스 & 객체

JJwoo·2024년 1월 3일
0

C#

목록 보기
8/20

🏗️ 클래스

객체지향 프로그래밍에서 데이터와 기능을 하나의 단위로 묶는 설계도 같은 역할을 한다.

클래스(Class)는 객체의 설계도로, 객체의 상태를 나타내는 필드(Field)와 행동을 정의하는 메서드(Method)로 구성된다.

클래스를 통해 생성된 실체가 객체(Object)이며, 각 객체는 클래스에 정의된 속성과 동작을 가진다.

클래스를 사용함으로써 데이터와 기능을 캡슐화하고, 코드의 재사용성과 유지보수성을 높일 수 있다.

객체를 생성하기 위해서는 클래스를 사용하여 인스턴스를 만들어야 한다.


📘 1. 객체지향 프로그래밍(Object-Oriented Programming, OOP)의 특징


🛡️ 캡슐화 (Encapsulation):

  • 관련된 데이터와 기능을 하나의 단위로 묶는 것을 의미

  • 클래스를 사용하여 데이터와 해당 데이터를 조작하는 메서드를 함께 캡슐화하여 정보를 은닉하고, 외부에서 직접적인 접근을 제한함으로써 안정성과 유지보수성을 높인다.


🔗 상속 (Inheritance):

  • 상속은 기존의 클래스를 확장하여 새로운 클래스를 만드는 메커니즘을 말함.

  • 부모 클래스(상위 클래스, 슈퍼 클래스)의 특성과 동작을 자식 클래스(하위 클래스, 서브 클래스)가 상속받아 재사용할 수 있다.

  • 코드의 중복을 줄이고, 클래스 간 계층 구조를 구성하여 코드의 구조화와 유지보수를 용이하게 한다.

  • 생성자 (Constructors): 객체를 초기화하는 역할을 한다. 객체가 생성될 때 자동으로 호출되며, 필드를 초기화하는 등의 작업을 수행한다.

  • 소멸자 (Destructors): 객체가 소멸될 때 호출되는 메서드로, 메모리나 리소스의 해제 등의 작업을 수행한다.


🔄 다형성 (Polymorphism):

  • 다형성은 하나의 인터페이스나 기능을 다양한 방식으로 구현하거나 사용할 수 있는 능력을 의미

  • 하나의 메서드 이름이 다양한 객체에서 다르게 동작할 수 있도록 하는 것으로, 오버로딩과 오버라이딩을 통해 구현될 수 있다.

  • 유연하고 확장 가능한 코드 작성을 가능하게 하며, 코드의 가독성과 재사용성을 높인다.


🎨 추상화 (Abstraction):

  • 추상화는 복잡한 시스템이나 개념을 단순화하여 필요한 기능에 집중하는 것을 의미

  • 클래스나 인터페이스를 사용하여 실제 세계의 개념을 모델링하고, 필요한 부분에 대한 명세를 정의

  • 세부 구현 내용을 감추고 핵심 개념에 집중함으로써 코드의 이해와 유지보수를 용이하게 한다.

🏢 객체 (Object)

  • 객체는 클래스로부터 생성된 실체로, 데이터와 해당 데이터를 조작하는 메서드를 가지고 있다.

  • 객체는 상태(데이터)행동(메서드)을 가지며, 실제 세계의 개체나 개념을 모델링한다.

  • 객체들 간의 상호작용을 통해 프로그램이 동작하고, 모듈화와 재사용성을 높여준다.


📐 2. 클래스 구성 요소

📦 1) 필드 (Fields)

  • 객체의 상태를 나타내는 변수로, 클래스 내부에 선언되어 데이터를 저장한다.

  • 객체의 특징이나 속성을 표현하며, 클래스의 멤버 변수로 선언된다.

  • 필드는 객체의 상태를 저장하고, 이를 통해 객체의 행동이 결정된다.

class Player
{
    // 필드 선언
    private string name;
    private int level;
}

⚙️ 2) 메서드 (Methods)

  • 객체가 수행할 수 있는 행동을 정의하는 함수로, 필요한 작업을 구현하고 실행하는 코드 블록이다.

  • 메서드는 객체의 상태를 변경하거나 다른 메서드를 호출하여 작업을 수행하고, 결과를 반환하기도 한다.

class Player
{
    //필드
    private string name;
    private int level;

    //메서드
    public void Attack()
    {
        // 공격 동작 구현
    }
}

메서드를 호출하기 위해서는 해당 메서드가 속해 있는 클래스의 인스턴스를 생성해야 한다.

이후 생성된 인스턴스를 통해 메서드를 호출할 수 있다.

Player player = new Player();  // Player 클래스의 인스턴스 생성
player.Attack();  // Attack 메서드 호출

🚀 3) 생성자 (Constructors)

  • 생성자는 객체가 생성될 때 자동으로 호출되는 특별한 메서드로, 객체를 초기화하는 역할을 한다.

  • 예를 들어, 필드의 초기값을 설정하거나 리소스를 할당하는 등의 작업을 한다.

  • 생성자는 매개변수에 따라 여러 형태로 오버로딩될 수 있다.

class Person
{
    private string name;
    private int age;

    public void PrintInfo()
    {
        Console.WriteLine($"Name: {name}, Age: {age}");
    }
}


//메인 함수
Person person1 = new Person();  // Person 클래스의 인스턴스 생성
person1.PrintInfo(); // PrintInfo 메서드 호출

🧹 4) 소멸자 (Destructors)

  • 객체가 소멸될 때 자동으로 호출되는 메서드.

  • 객체가 더 이상 사용되지 않을 때 필요한 정리 작업을 수행하고, 리소스를 해제하는 데 사용된다.

  • C#에서는 가비지 컬렉터에 의해 자동으로 메모리 관리가 이루어지기 때문에 소멸자를 직접 작성하는 경우는 드물다.

class Person
{
    private string name;

    public Person(string newName)
    {
        name = newName;
        Console.WriteLine("Person 객체 생성");
    }

    ~Person()
    {
        Console.WriteLine("Person 객체 소멸");
    }
}

🏡 프로퍼티 (Property)

  • 클래스의 멤버이자 필드에 대한 접근을 제어하는 메서드로, 필드의 값을 읽거나 수정할 수 있는 방법을 제공한다.
  • getset 접근자 메서드로 구성되어, 필드의 값을 읽거나 쓰는 로직을 구현
  • 필드에 대한 접근 제어와 데이터 유효성 검사 등을 수행할 수 있다.

  • 필드에 직접 접근하는 것을 방지하고, 필드 값을 변경하거나 검증하는 로직을 추가할 수 있으며, 이를 통해 데이터의 무결성과 안전성을 보장할 수 있다.

get 접근자는 프로퍼티의 값을 반환하고, set 접근자는 프로퍼티의 값을 설정

필요에 따라 get 또는 set 접근자 중 하나를 생략하여 읽기 전용 또는 쓰기 전용 프로퍼티를 정의할 수 있다.

[접근 제한자] [데이터 타입] 프로퍼티명
{
    get
    {
        // 필드를 반환하거나 다른 로직 수행
    }
    set
    {
        // 필드에 값을 설정하거나 다른 로직 수행
    }
}
class Person
{
    private string name;
    private int age;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public int Age
    {
        get { return age; }
        set { age = value; }
    }
}
Person person = new Person();
person.Name = "John";   // Name 프로퍼티에 값 설정
person.Age = 25;        // Age 프로퍼티에 값 설정

Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");  // Name과 Age 프로

🎞 자동 프로퍼티 (Auto Property)

- 자동 프로퍼티는 프로퍼티를 간단하게 정의하고 사용할 수 있는 편리한 기능입니다.
- 필드의 선언과 접근자 메서드의 구현을 컴파일러가 자동으로 처리하여 개발자가 간단한 구문으로 프로퍼티를 정의할 수 있습니다.
    [접근 제한자] [데이터 타입] 프로퍼티명 { get; set; }
    
class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Person person = new Person();
person.Name = "John";     // 값을 설정
person.Age = 25;          // 값을 설정

Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");  // 값을 읽어 출력

✔ 2주차 연습 문제

1) 구구단

1부터 9까지의 숫자를 각각 1부터 9까지 곱한 결과를 출력하는 프로그램.

using System;

class Program
{
    static void Main()
    {
        for(int i = 1; i <= 9; i++)
        {
            for(int j = 1; j <= 9; j++)
            {
                Console.WriteLine(i + " x " + j + " = " + i*j);
            }
        }
    }
}

초보자의 관점:

  • 개념 이해: 구구단은 두 숫자의 일련의 곱이라는 것을 인식

  • 패턴 식별: 곱셈표의 각 행은 1부터 9까지의 숫자와 고정된 숫자의 곱을 나타낸다.

  • 시각화: 각 행이 숫자의 곱셈표인 그리드를 상상해 보기, 이는 중첩 루프의 작동 방식을 시각화하는 데 도움이 된다.

  • 구현: 중첩 루프를 사용, 외부 루프는 테이블을 원하는 숫자를 반복하고, 내부 루프는 곱하는 숫자를 반복.

구구단 풀이

코드 분석:

  • 외부 루프: 외부 루프(for(int i = 1; i <= 9; i++))는 1부터 9까지의 숫자를 반복한다.. 이 루프의 각 반복은 다른 곱셈표를 나타낸다. (예: 'i' 테이블).

  • 내부 루프: 내부 루프(for(int j = 1; j <= 9; j++))도 1에서 9까지 반복한다. i가 반복될 때마다 i에 다음을 곱한다.
    각 'j'(1부터 9까지).

  • 곱셈 및 출력: 내부 루프 내에서 프로그램은 i와 j의 곱을 계산하고 i x j = 곱 형식으로 출력한다.


2) 별 찍기

  1. 오른쪽으로 기울어진 직각삼각형 출력하기:
    • 이 부분에서는 for 루프를 사용하여 오른쪽으로 기울어진 직각삼각형을 출력하는 프로그램을 작성해야 합니다. 삼각형의 높이는 5입니다.
  2. 역직각삼각형 출력하기:
    • 역직각삼각형을 출력하는 프로그램을 작성해야 합니다. 이 삼각형의 높이 역시 5입니다.
  3. 피라미드 출력하기:
    • 피라미드를 출력하는 프로그램을 작성해야 합니다. 이 피라미드의 높이는 5입니다.
    class Program
{
    static void Main(string[] args)
    {
        // 직각삼각형 출력하기
        for (int i = 1; i <= 5; i++)
        {
            for (int j = 1; j <= i; j++)
            {
                Console.Write("*");
            }
            Console.WriteLine();
        }

        Console.WriteLine();

        // 역직각삼각형 출력하기
        for (int i = 1; i <= 5; i++)
        {
            for (int j = 5; j >= i; j--)
            {
                Console.Write("*");
            }
            Console.WriteLine();
        }

        Console.WriteLine();

        // 피라미드 출력하기
        for (int i = 1; i <= 5; i++)
        {
            for (int j = 5 - i; j > 0; j--)
            {
                Console.Write(" ");
            }
            for (int k = 1; k <= (2 * i) - 1; k++)
            {
                Console.Write("*");
            }
            Console.WriteLine();
        }

    }
}

초보자의 관점:

종이나 머릿 속에 이러한 모양을 그리는 것부터 시작해본다.
각 행의 별표 수가 어떻게 변하는지 확인.

패턴 확인: 직각삼각형의 경우 별표 개수는 행 번호와 동일하다. 역삼각형의 경우,

정삼각형:

  • 행에 대한 루프: 외부 루프(for (int i = 1; i <= 5; i++))는 삼각형의 각 행을 나타냅니다.

  • 별표에 대한 루프: 내부 루프(for (int j = 1; j <= i; j++))는 별표를 인쇄합니다. 별표 수는 각 행마다 증가합니다(첫 번째 행에 1개, 두 번째 행에 2개 등).

역직각삼각형:

  • 별의 전체 라인을 생각해 보세요:
    5개의 별이 있는 라인을 상상하는 것부터 시작, 이것은 삼각형 상단의 첫 번째 행

  • 별표를 하나씩 제거: 새 줄마다 끝에서 별 하나를 제거합니다. 따라서 별 5개가 있는 첫 번째 줄 이후 다음 줄에는 별 4개가 있고, 그 다음에는 별 3개가 있는 식으로 별이 1개만 남을 때까지 계속

코드 설명:

  • 행에 대한 루프: 외부 루프(for (int i = 1; i <= 5; i++))는 각 행을 통과합니다. 총 5개의 행이 있습니다.

  • 별에 대한 루프: 내부 루프(for (int j = 5; j >= i; j--))는 별을 처리합니다. 별 5개로 시작하고 외부 루프가 다음 행으로 이동할 때마다 별 1개씩 감소합니다.

피라미드:

  • 간격으로 시작: 피라미드는 위쪽으로 갈수록 좁아지기 시작하여 점점 넓어집니다. 하지만 그것도 중심을 잡아야 합니다. 따라서 각 행은 왼쪽에 공백을 두고 시작합니다.

  • 각 행마다 더 많은 별 추가: 맨 위에 별 1개부터 시작하세요. 더 많은 별을 추가하면 각각의 새 행이 더 넓어집니다. 두 번째 행에는 별 3개, 그 다음에는 5개 등이 있습니다.

코드 설명:

  • 행에 대한 루프: 다시 외부 루프(for (int i = 1; i <= 5; i++))는 피라미드의 각 행에 대한 것입니다.

  • 공백에 대한 루프: 별 앞에는 공백에 대한 루프가 있습니다(for (int j = 5 - i; j > 0; j--)). 이 루프는 별이 중앙에 있는지 확인합니다. 행 아래로 내려갈수록 공백 수가 줄어듭니다.

  • 별에 대한 루프: 별 루프(for (int k = 1; k <= (2 * i) - 1; k++))는 별을 추가합니다. 별의 수는 1개부터 시작하여 각 행에 위의 별보다 2개의 별이 더 많아지는 방식으로 증가합니다

3) 최대값, 최소값 찾기

using System;

class Program
{
    static void Main()
    {
        int[] numbers = new int[5]; // 5개의 정수를 저장할 배열 선언
        for(int i = 0; i < 5; i++)
        {
            Console.Write("숫자를 입력하세요: "); // 사용자에게 숫자 입력 요청
            numbers[i] = int.Parse(Console.ReadLine()); // 사용자가 입력한 값을 배열에 저장
        }

        int max = numbers[0]; // 최대값을 배열의 첫 번째 요소로 초기화
        int min = numbers[0]; // 최소값을 배열의 첫 번째 요소로 초기화

        for(int i = 1; i < 5; i++)
        {
            if(numbers[i] > max) // 현재 요소가 최대값보다 크다면
            {
                max = numbers[i]; // 현재 요소를 새로운 최대값으로 설정
            }
            if(numbers[i] < min) // 현재 요소가 최소값보다 작다면
            {
                min = numbers[i]; // 현재 요소를 새로운 최소값으로 설정
            }
        }

        Console.WriteLine("최대값: " + max); // 계산된 최대값 출력
        Console.WriteLine("최소값: " + min); // 계산된 최소값 출력
    }
}

간단한 코드 설명:

이 코드는 숫자를 저장하고, 그 중에서 가장 큰 숫자와 가장 작은 숫자를 찾는 과정을 나타냅니다. 여기 간단한 설명이 있습니다:

숫자 저장: 프로그램은 먼저 5개의 숫자를 저장할 수 있는 공간을 만듭니다. 이것은 숫자를 보관할 상자와 같습니다.

사용자 입력 받기: 다음으로, 프로그램은 사용자에게 숫자를 입력하라고 요청합니다. 이 숫자들은 앞서 만든 상자에 하나씩 저장됩니다.

가장 큰 숫자와 가장 작은 숫자 찾기: 프로그램은 첫 번째 숫자를 가장 크고 가장 작은 숫자로 가정합니다. 그리고 나머지 숫자들을 하나씩 확인하면서, 만약 더 큰 숫자를 발견하면 그 숫자를 '가장 큰 숫자'로, 더 작은 숫자를 발견하면 그 숫자를 '가장 작은 숫자'로 갱신합니다.

결과 표시: 모든 숫자를 확인한 후, 프로그램은 가장 큰 숫자와 가장 작은 숫자를 화면에 표시합니다.

간단히 말해서, 이 코드는 각 숫자를 하나씩 확인하면서 가장 큰 숫자와 가장 작은 숫자를 기억하면서 가장 큰 숫자와 가장 작은 숫자를 찾는 게임과 같습니다.

2-4 소수 판별하기

using System;

class Program
{
    // 주어진 숫자가 소수인지 판별하는 함수
    static bool IsPrime(int num)
    {
        if (num <= 1) // 1보다 작거나 같은 수는 소수가 아니다.
        {
            return false;
        }
        for (int i = 2; i * i <= num; i++) // 2부터 숫자의 제곱근까지만 확인한다.
        {
            if (num % i == 0) // 숫자가 i로 나누어 떨어진다면 소수가 아니다.
            {
                return false;
            }
        }
        return true; // 소수인 경우
    }

    static void Main()
    {
        Console.Write("숫자를 입력하세요: "); // 사용자에게 숫자 입력 요청
        int num = int.Parse(Console.ReadLine()); // 사용자가 입력한 값을 정수로 변환하여 저장

        if (IsPrime(num)) // 입력 받은 숫자가 소수라면
        {
            Console.WriteLine(num + "은 소수입니다."); // 소수임을 출력
        }
        else // 소수가 아니라면
        {
            Console.WriteLine(num + "은 소수가 아닙니다."); // 소수가 아님을 출력
        }
    }
}

코드 리뷰

이 함수는 하나의 숫자를 받아서 그 숫자가 소수인지 아닌지를 판별합니다.

  • 소수란?:
    '1과 자기 자신 외의 약수를 가지지 않는 1보다 큰 자연수'
    예를 들어, 2, 3, 5, 7 등이 소수입니다.
  • 소수 판별 과정:
    1보다 작거나 같은 경우: 숫자가 1보다 작거나 같으면 바로 소수가 아님을 결정합니다.

  • 나머지 경우:
    숫자가 2 이상인 경우, 2부터 그 숫자의 제곱근까지만 나눠보며, 나누어 떨어지는지 확인합니다. 만약 중간에 나누어 떨어지면 소수가 아닙니다.

메인 함수 (Main) 로직:

  • 사용자 입력: 프로그램은 사용자에게 숫자 하나를 입력하라고 요청합니다.

  • 소수 판별: 입력받은 숫자를 IsPrime 함수에 넘겨 소수인지 판별합니다.

  • 결과 출력: 입력받은 숫자가 소수라면 "소수입니다"라고 출력하고, 소수가 아니라면 "소수가 아닙니다"라고 출력합니다.

초보자 관점에서의 접근:

먼저, 소수가 무엇인지 이해합니다.

다음으로, 코드가 어떻게 소수를 판별하는지를 이해합니다. 여기서 중요한 것은 모든 숫자를 하나씩 나눠보는 것이 아니라, 제곱근까지만 확인하는 것입니다. 이는 계산을 훨씬 빠르게 만들어 줍니다.

마지막으로, 사용자로부터 입력을 받고 그 결과를 출력하는 방법을 이해합니다.

이 코드를 통해, 사용자가 입력한 숫자가 소수인지 아닌지를 효율적으로 판별할 수 있습니다.

profile
개발 모코코

0개의 댓글