본문 바로가기

프로그래머스 풀스택 데브코스/데브코스 TIL

웹 풀사이클 데브코스 TIL 47일차

클래스

클래스는 사용자 정의 데이터타입이다. 데이터와 메소드를 사용자인 내가 새로 정의한 데이터 타입. 맴버 변수와 맴버 함수로 구성된다.
사물의 특성을 정리항 필드와 메소드로 표현하는 과정이 추상화이다.

접근 지정자

  • public : 누구나 접근 가능
  • private : 클래스 내부에서만 접근 가능하고, 외부에서는 접근할 수 없다.
  • protected: 상속관계에 있을 떼 상속받은 자식 클래스에서 접근 가능하다.

객체

클래스를 통해 선언한 변수를 객체라고 한다.

Dog a = new Dog();

c언어의 malloc과 new 연산자는 같은 역할을 한다. 객체는 Heap 메모리에 생성된다. a에는 객체의 주소가 들어가 있다.
다음은 객체의 사용 예시이다.

using System;

class Dog{
    private int eyes, nose, mouth, ears;

    public void bark() {
        Console.WriteLine("Bark!");
    }
}

class HelloWorld {
  static void Main() {
      Dog a = new Dog();
      a.bark();
  }
}
//Bark!

public 메소드인 bark를 호출해보았다.

생성자

모든 변수는 선언이 되면 값을 초기화 해야한다. 객체도 본질적으로 변수이므로 초기화를 해야한다. 객체 생성 시 초기화 전용 메소드를 제공하는데 이를 생성자라 한다. 생성자는 객체 생성 시 자동으로 호출된다.

    public Dog(){
        eyes = 0;
        nose = 0;
        mouth = 0;
        ears = 0;
    }

생성자의 기본 형태이다. 생성자에는 몇가지 규칙이 있다. 먼저 클래스 이름과 생성자 이름이 같아야 한다. 그리고 return 타입이 필요 없으므로 따로 지정해 주지 않아도 된다.

상속

클래스에서는 상속이 가능하다. 상속을 해주는 클래스를 부모 클래스, 상속을 받는 클래스를 자식 클래스라고 한다. 이미 완성된 클래스를 다른 클래스에 상속할 수 있다.

class Dog{
    protected int eyes, nose, mouth, ears;
    public void bark() {
        Console.WriteLine("Bark!");
    }
    public Dog(){
        eyes = 0;
        nose = 0;
        mouth = 0;
        ears = 0;
    }
}

class Poodle : Dog{
    public Poodle(){
        base.eyes = 2;
        Console.WriteLine("푸들 눈 : {0}", eyes);
    }
}

class HelloWorld {
  static void Main() {
      Dog a = new Dog();
      a.bark();
      Poodle pd = new Poodle();
  }
}

상속 예제 코드이다. Dog 클래스를 상속하는 Poodle 클래스를 만들었다. 자식 클래스는 부모 클래스의 맴버들을 사용할 수 있는데, 이때 사용하기 위해서는 부모 클래스의 멤버들을 protected로 선언해주어야한다. protected로 선언하면 아예 외부에서는 접근이 불가능하고 자식은 접근이 가능하다. base 라는 키워드는 부모 객체를 나타낸다.

다형성

함수의 이름이 같더라도 전달인자의 타입이나 갯수에 따라 구분된다. 오버로딩과 오버라이딩 기법이 있다.

오버로딩

겉모습은 똑같지만 내용이 다른 경우. 이름이 같은 함수일지라도 전달인자 타입이나 갯수가 다른 경우

int Plus(int a, int b) {
    return a+b;
}
char Plus(char a, char b) {
    return a+b;
}

오버로딩의 예시를 알아보자.

public class Zerg{
    public void Overload(int zerggling) {
        Console.WriteLine("저글링 {0} 마리", zerggling);
    } 
    public void Overload(int zerggling, int hydra) {
        Console.WriteLine("저글링 {0} 마리 + 히드라 {1} 마리", zerggling, hydra);
    } 
    public void Overload(int zerggling, int hydra, int lurker) {
        Console.WriteLine("저글링 {0} 마리 + 히드라 {1} 마리 + 럴커 {2} 마리", zerggling, hydra, lurker);
    } 
    public void Overload(char zerggling) {
        Console.WriteLine("저글링 {0} 등급", zerggling);
    } 
}

class HelloWorld {
  static void Main() {
    Zerg zerg = new Zerg();
    zerg.Overload(10);
    zerg.Overload(10, 20);
    zerg.Overload(10, 20, 30);
    zerg.Overload('A');
  }
}

Overload 라는 4개의 함수가 오버로딩 되었고, 매개변수가 어떻게 전달되느냐에 따라 다른 함수가 호출되는 것을 알 수 있다.

오버라이딩

무언가에 올라타서 기존의 것을 덮어 버린다는 개념

class Dog{
    protected int eyes, nose, mouth, ears;
    virtual public void bark() {
        Console.WriteLine("Bark!");
    }
    public Dog(){
        eyes = 0;
        nose = 0;
        mouth = 0;
        ears = 0;
    }
}

class Poodle : Dog{
    public Poodle(){
        base.eyes = 2;
        Console.WriteLine("푸들 눈 : {0}", eyes);
    }

    public override void bark() {
        Console.WriteLine("왈왈!");
    }
}
class HelloWorld {
  static void Main() {
    Dog dog = new Dog();
    dog.bark();
    Poodle pd = new Poodle();
    pd.bark();

    dog = new Poodle();
    dog.bark();
  }
}

자식 클래스에서 부모 클래스의 함수를 재정의 하였다. Dog 타입 변수에 Poodle 객체를 넣을 수 있을까? 가능하다. 부모는 자식을 품을 수 있다. dog.bark()는 안에 실제 들어있는 객체에 맞게 푸들의 bark가 호출된다.

인터페이스

메소드의 목록만을 가지고 있는 명세, 사용자 정의 타입. 메소드의 목록만 선언하고 구현은 하지 않는다. 인터페이스를 상속한 클래스는 명세된 메소드를 반드시 구현해야한다.

인터페이스를 사용하는 이유?
기존의 기능을 추가하거나 수정의 개념보다는 동일한 개념의 기능을 새롭게 구현하는 기능이다. 공동작업 시 표준을 정하는 역할
일반적으로 클래스를 상속하는 이유는 기능의 확장이 목적이지만, 인터페이스는 어떤 기능을 구현할 지를 정하는게 목적이다.

public interface IUnit{
    void Attack();
    void Move();
}

public class Zergling : IUnit {
    public void Attack(){
        Console.WriteLine("저글링 : 공격한다.");
    }
    public void Move(){
        Console.WriteLine("저글링 : 이동한다.");
    }
}
public class Dragoon : IUnit {
    public void Attack(){
        Console.WriteLine("드라군 : 공격한다.");
    }
    public void Move(){
        Console.WriteLine("드라군 : 이동한다.");
    }
}
class HelloWorld {
  static void Main() {
    Zergling zerg = new Zergling();
    zerg.Attack();
    zerg.Move();

    Dragoon dragoon = new Dragoon();
    dragoon.Attack();
    dragoon.Move();
  }
}

인터페이스를 사용하는 예시 코드이다.

메모리 관리

플랫폼 기반의 객체 지향 언어는 가비지 컬렉터가 메모리를 자동 관리한다.
백그라운드에서 더 이상 사용되지 않는 메모리를 찾아 회수한다. 메모리를 할당하고 회수하고를 계속 반복하다보면 시간이 흐른후 중간중간 빈 공간이 생긴다. 이를 단편화 현상이라고 한다. 남아있는 메모리를 이동시켜 큰 덩어리로 만들어주는 것을 컴팩션이라고 한다.

익명메소드

  • 메소드를 미리 정의하지 않고 사용할 때 정의한다.
  • 익명 메소드를 사용하면 코드가 간결해진다.
  • 익명 메소드는 별도의 메소드를 만들지 않으므로 오버헤드를 줄일 수 있다.
  • 익명 메소드는 내용이 복잡하면 안된다.
  • 익명 메소드는 람다식에서 사용된다.
class HelloWorld {

  delegate int CalcDele(int x);
  static void Main() {
    CalcDele d = delegate (int x) {
        return x+1;
    };

    Console.WriteLine(d(3));
  }
}

람다식

기존 익명 메소드를 더욱 간결하게 만들기 위해 만들어진 문법. 코드를 짧고 간결하게 표현하는 것이 목적.

class HelloWorld {

  delegate int CalcDele(int x);
  static void Main() {
    CalcDele d = x => x+1;

    Console.WriteLine(d(3));
  }
}

후기

클래스와 인터페이스, 람다식에 대해서 제대로 알아보았다. 아후에 타입스크립트 학습에 있어서도 중요한 개념인 것 같다.

키워드: 프로그래머스 데브코스, 국비지원교육, 코딩부트캠프