Unity 내일배움캠프 TIL 0815 | C# 기초 | 상속과 다형성 | 제너릭 | out과 ref

cheeseonrose·2023년 8월 15일
0

Unity 내일배움캠프

목록 보기
9/89
post-thumbnail

오늘은 공휴일!! 이라서 그냥 쉬고 싶었는데
뭔가 3주차 애매하게 강의 하나만 들은게 걸리적거려서
그냥 강의만 오늘 다 듣고 과제는 내일 하는걸루~~~ 히히

상속

개념

  • 기존의 클래스(부모 클래스/상위 클래스)를 확장하거나 재사용하여 새로운 클래스(자식 클래스/하위 클래스)를 생성하는 것
  • 자식 클래스는 부모 클래스의 멤버(필드, 메서드, 프로퍼티)를 상속받아 사용 가능

장점

  • 코드의 재사용
  • 계층 구조 표현
  • 유지보수성 향상

종류

  • 단일 상속 : 하나의 자식 클래스가 하나의 부모 클래스만 상속받음
  • 다중 상속 : 하나의 자식 클래스가 여러 개의 부모 클래스를 동시에 상속받음 but C#에서는 다중 상속 지원 X (인터페이스만 가능)
  • 인터페이스 상속 : 클래스가 인터페이스를 상속받는 것

특징

  • 부모 클래스의 멤버에 접근 가능
  • 부모 클래스의 메서드 재정의
  • 상속의 깊이 : 다수의 계층적인 상속 구조 가능

접근 제한자와 상속

  • 부모 클래스의 멤버 접근 제한자에 따라 자식 클래스에서 해당 멤버에 접근할 수 있는 범위가 결정됨
// 부모 클래스
public class Animal
{
	public string Name { get; set; }
    
    public int Age { get; set; }
    
    public void Eat()
    {
    	Console.WriteLine("Animal is eating");
    }
    
    public void Sleep()
    {
    	Console.WriteLine("Animal is sleeping");
    }
}

// 자식 클래스
public class Dog : Animal
{
	public void Bark()
    {
    	Console.WriteLine("Dog is bark");
    }
}

public class Cat : Animal
{
	public void Meow()
    {
    	Console.WriteLine("Cat is meow.");
    }
    
    public void Sleep()
    {
    	Console.WriteLine("Cat Sleep!");
    }
}

static void Main(string[] args)
{
	Dog dog = new Dog();
    dog.Name = "Potato";
    dog.Age = 3;
    
    dog.Eat();
    dog.Sleep();
    dog.Bark();
    
    Cat cat = new Cat();
    cat.Name = "Tomato";
    cat.Age = 5;
    
    cat.Eat();
    cat.Sleep();
    cat.Meow();
}
Animal is eating
Animal is sleeping
Dog is bark
Animal is eating
Cat Sleep!
Cat is meow.



다형성

  • 같은 타입이지만 다양한 동작을 수행할 수 있는 능력

가상(Virtual) 메서드

  • 기본적으로 부모 클래스에서 정의되고, 자식 클래스에서 필요에 따라 재정의할 수 있는 메서드
  • virtual 키워드 사용
  • 예시
    public class Unit
     {
    	public void Move() 
      	{
      		Console.WriteLine("두 발로 걷기");
         }
         
        public void Attack()
        {
        	Console.WriteLine("Unit 공격");
        }
     }
     
     public class Marine : Unit
     {
     
     }
     
     public class Zergling : Unit
     {
     	public void Move()
      	{
          	Console.WriteLine("네 발로 걷기");
        }
     }
     
     static void Main(string[] args)
     {
     	Marine marine = new Marine();
      	marine.Move();
        marine.Attack();
        
        Zergling zergling = new Zergling();
        zergling.Move();
        zergling.Attack();
     }
    두 발로 걷기
     Unit 공격
     네 발로 걷기
     Unit 공격
    • 많은 수의 Marine과 Zergling들을 함께 관리하기 위해 Unit을 담는 list를 생성
      • Marine과 Zergling의 Move가 아닌 Unit의 Move가 실행됨
      static void Main(string[] args)
       {
       	// Unit : 참조의 형태
      	// Marine, Zergling : 실제 형태
          List<Unit> list = new List<Unit>();
          list.Add(new Marine());
          list.Add(new Zergling());
          
          foreach (Unit unit in list)
          {
          	unit.Move();
          }
       }
      두 발로 걷기
       두 발로 걷기
    • Unit의 Move를 virtual로 선언 -> 자식 클래스가 이 메서드를 재정의했을 수도 있음을 알려줌
    • Zergling은 Move 선언시 override 명시
      • Move 실행시 자식 클래스에 방문해서 Move 함수를 재정의했는지 확인 -> 재정의한 함수를 먼저 사용
      public class Unit
       {
      	public virtual void Move() 
      	{
      		Console.WriteLine("두 발로 걷기");
          }
          ...
       }
       
       public class Zergling : Unit
       {
       	public override void Move()
      	{
          	Console.WriteLine("네 발로 걷기");
          }
       }
      두 발로 걷기
       네 발로 걷기

추상(Abstract) 클래스와 메서드

  • 추상 클래스 : 직접적으로 인스턴스를 생성할 수 없는 클래스로, 상속을 위한 베이스 클래스로 사용됨
  • 추상 메서드 : 구현부가 없는 메서드로, 자식 클래스에서 반드시 구현되어야 함
  • 가상 메서드와의 차이점 : 자식 클래스에게 강제성을 부여함 -> 무조건 재정의해야 한다!
abstract class Shape
{
	public abstract void Draw();
}

class Circle :  Shape
{
	public override void Draw()
    {
    	Console.WriteLine("Drawing Circle");
    }
}

class Square : Shape
{
	public override void Draw()
    {
    	Console.WriteLine("Drawing Square");
    }
}

class Triangle : Shape
{
	public override void Draw()
    {
    	Console.WriteLine("Drawing Triangle");
    }
}

static void Main(string[] args)
{
	// Shape shape = new Shape(); -> 객체화 불가능
    List<Shape> list = new List<Shape>();
    list.Add(new Circle());
    list.Add(new Square());
    list.Add(new Triangle());
    
    foreach (Shape shape in list)
    {
    	// Draw는 abstract이므로 무조건 재정의가 되어있음 -> 자식 클래스 방문
    	shape.Draw(); 
    }
}
Drawing Circle
Drawing Square
Drawing Triangle

오버라이딩과 오버로딩

  • 오버라이딩(Overriding) : 부모 클래스에서 이미 정의된 메서드를 자식 클래스에서 재정의하는 것
    • 상속 관계에 있는 클래스 간에 발생
    • 이름, 매개변수, 반환 타입이 동일해야 함
  • 오버로딩(Overloading) : 동일한 메서드 이름을 가지고 있지만, 매개변수의 개수, 타입 또는 순서가 다른 여러 개의 메서드를 정의하는 것



제너릭

정의

  • 클래스나 메서드를 일반화시켜 다양한 자료형에 대응할 수 있는 기능
    • 코드의 재사용성 ↑

사용법

  • <T> 형태의 키워드를 이용하여 선언
    (꼭 T가 아니어도 되지만 일반적으로 T를 사용)
  • 제너릭 클래스나 메서드에 사용할 자료형은 선언 시점이 아닌 사용 시점에 결정됨
  • 제너릭 클래스나 메서드 사용시에는 <T> 대신 구체적인 자료형을 넣어줌
class Stack<T>
{
	private T[] elements;
    private int top;
    
    public Stack()
    {
    	elements = new T[100];
    	top = 0;
    }
    
    public void Push(T item)
    {
    	elements[top++] = item;
    }
    
    public T Pop()
    {
    	return elements[--top];
    }
}

static void Main(string[] args)
{
	Stack<int> intStack = new Stack<int>();
    intStack.Push(1);
    intStack.Push(2);
    intStack.Push(3);
    Console.WriteLine(intStack.Pop());
}
  • 제너릭을 두 개 이상 사용
    class Pair<T1, T2>
     {
    	public T1 First { get; set; }
      	public T2 Second { get; set; }
          
        public Pair(T1 first, T2 second)
        {
        	First = first;
          	Second = second;
        }
        
        public void Display()
        {
        	Console.WriteLine($"First: {First}, Second: {Second}");
        }
     }
    Pair<int, string> pair1 = new Pair<int, string>(1, "One");
     pair1.Display();
     
     Pair<double, bool> pair2 = new Pair<double, bool>(3.14, true);
     pair2.Display();
    First: 1, Second: One
     First: 3.14, Second: True



out과 ref

정의

  • 메서드에서 매개변수를 전달할 때 사용

사용법

  • out : 메서드에서 반환 값을 매개변수로 전달하는 경우 사용
  • ref : 메서드에서 매개변수를 수정하여 원래 값에 영향을 주는 경우 사용
  • 메서드에서 값을 반환하는 것이 아닌, 매개변수를 이용하여 값을 전달 가능
  • 차이점 : out으로 선언된 매개변수에는 메서드에서 값을 꼭 넣어줘야 함. ref는 값을 넣어주지 않아도 상관 없음.
// out 키워드 예시
static void Divide(int a, int b, out int quotient, out int remainder)
{
	quotient = a / b;
	remainder = a % b;
}

// ref 키워드 예시
static void Swap(ref int a, ref int b)
{
	int temp = a;
	a = b;
	b= temp;
}

static void Main(string[] args)
{
	int quotient, remainder;
    Divide(7, 3, out quotient, out remainder);
    Console.WriteLine($"{quotient}, {remainder}");
    
    int x = 1, y = 3;
    Swap(ref x, ref y);
    Console.WriteLine($"{x}, {y}");
}

주의사항

  1. ref로 인한 값의 변경 가능성
  2. 성능 이슈
    • ref는 매개변수 값을 복사하지 않고 메서드 내에서 직접 접근할 수 있으므로 성능상 이점이 있지만, 가독성과 유지보수성이 저하됨
  3. 변수 변경 여부
    • out 매개변수를 전달할 때 해당 변수의 이전 값이 유지되지 않음에 주의



깃허브에 업로드한 md 파일 보기좋게 정리 좀 하고 마무리 해야겠당
오늘 공부는 여기까지
끗~

0개의 댓글