2주차(3)-C# 문법 강의 3주차 내용-2
상속의 다형성
1.상속
객체지향에서 아주 중요한 개념
1)상속이란?
기존의 클래스(부모 혹은 상위 클래스)를 확장하거나 재사용하여
새로운 클래스(자식 혹은 하위 클래스)를 생성하는 것이다.
자식 클래스는 부모 클래스의 멤버(필드, 메서드, 프로퍼티 등) 을
상속받아 사용할 수 있다.
상속을 통해 부모 클래스의 기능을 확장하거나 새로운 클래스를 정의할 수 있다.
2)상속의 장점
코드의 재사용성 : 기존 클래스의 데이터를 사용할 수 있으므로
반복적인 코드 작성을 줄일 수 있다.
계층 구조의 표현 : 코드 구조가 명확해진다
유지 보수성의 향상 : 위와같은 이유로 유지 보수성이 향상됨
부모 클래스 수정/버그픽스 를 진행하면
자식 클래스들도 한번에 고쳐지니 더 편해짐
3)상속의 종류
단일 상속 : 하나의 자식 클래스가 하나의 부모 클래스만 상속받는 것
C#은 단일 상속을 지원
다중 상속 : 하나의 자식 클래스가 여러 개의 부모 클래스를 동시에 상속받는 것
C#은 다중 상속을 지원하지 않음
인터페이스 상속 : 클래스가 인터페이스를 상속받는 것
인터페이스는 다중 상속을 지원하며, 클래스는 하나의 클래스와
여러개의 인터페이스를 동시에 상속받을 수 있다.
4)상속의 특징
부모 클래스의 멤버에 접근, 사용 가능(변수, 함수)
재정의 하여 자신에게 맞게 수정하거나 확장 가능(다형성)
상속의 깊이 : 단일 상속을 계속 이어서 하는것도 가능
부모 -> 자식 -> 자식 -> 자식
하지만 이렇게하면 클래스간의 관계가 복잡해져 알아보기 힘들 수 있으니 주의
5)접근 제한자의 상속
필요에 따라 조절하면 캡슐화나 정보 은닉을 구현할 수 있다.
2.자식 객체에 부모를 상속하는법
자식객체의 class에 : 부모클래스 만 해주면 된다
예시
public class Dog : Animal // Dog이라는 자식 클래스가 Animal이라는 부모 클래스를 상속받았다.
우리가 스크립트를 생성할 때 항상 보던
public class 스크립트 명 : MonoBehavior이
우리의 스크립트는 기본적으로
MonoBehavior를 상속받는다는 뜻이였다!
이러면 자식 클래스는 자신이 가진 필드/메서드에 더해서
부모 클래스의 필드/메서드까지 사용이 가능하다!
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 = "Bobby";
dog.Age = 3;
dog.Eat();
dog.Sleep();
dog.Bark();
Cat cat = new Cat();
cat.Name = "Kkami";
cat.Age = 10;
cat.Eat();
cat.Sleep();
cat.Meow();
}
}
일단 Dog는 그대로 사용하였고
이 때 자식 클래스 Dog의 메모리 구조를 보자면
앞부분에 Animal, 뒷부분에 Dog가 붙은 형태로 볼 수 있다.
Cat 클래스의 경우는 살짝 변형을 하였는데,
Cat에서 다시 작성된 Sleep는 Cat에 복사되어 오는 Sleep을 덮어씌운다.
호출 시 더 관계성이 있는 클래스에서 메서드를 가져온다.
(여기선 Cat class)
하지만 Cat의 경우는 다형성을 살린게 아니라 단순히 숨기고 보여준 것 뿐이므로
문제가 발생할 수 있다. 그게 뭐냐
Unit(부모 클래스)에서 메서드를 찾는 경우
자식 클래스에서 메서드를 재구현 했더라도
결국 부모클래스의 메서드를 사용하므로
숨기는 건 결국 좋지 않은 방향이다.
3.상속의 다형성 살리기
위의 숨기기를 대체하는 해결책이 이것이다.
1)가상(Virtual) 메서드
가상 메서드는 기본적으로 부모 클래스에서 정의되고
자식 클래스에서 재정의 할 수 있는 메서드이다.
가상 메서드는 virtual 키워드를 통해 선언되며, 자식 클래스에서
필요에 따라(재정의 할 필요 없음) 재정의 될 수 있음
이를 통해 자식 클래스에서 부모 클래스의 메서드를 변경하거나 확장함
예시)
internal class Program
{
public class Unit
{
public virtual void Move() // 자식이 재정의를 했을 수 있다.
{
Console.WriteLine("두발로 걷기");
}
public void Attack()
{
Console.WriteLine("Unit 공격");
}
}
public class Marine : Unit
{
}
public class Zergling : Unit
{
//네발로 걷는 동작
public override 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();
//현재 유닛으로 참조를 하고있고
List<Unit> list = new List<Unit>();
list.Add(new Marine());
list.Add(new Zergling());
//실행 형태는 저글링과 마린이다.
foreach(Unit unit in list) //유닛 안에 리스트의 정보들을 넣어준다.
{
unit.Move();
}
}
}
부모 클래스에서 재정의가 필요한 함수를 virtual 로 가상 메서드로 만들어 주고
public virtual void Move() // 자식이 재정의를 했을 수 있다.
자식 클래스에서 상속받은 동일한 함수에 override를 붙이면 된다.
public override void Move() // 재정의 하겠다고 표시함
virtual 함수는
부모 객체를 참조하는경우
내가 부모객체가 맞지만 virtual이 달린 함수는 실제 형태가 다를 수 있다.
그러니 실행 함수로 가서 재정의 되었는지 확인하여 봐라 라는 뜻.
이것은 virtual메서드를 부를 때 마다 확인한다.
다르다면 재정의 된 메서드를 사용한다.
요약
부모 클래스 참조할 때, 자식 클래스가 상속받은 함수를 변경하여 사용하고 있다면
똑같은 메서드 이름을 사용해 숨기지 말고
virtual & override로 재정의 확인&재정의 해주는게 좋다.
===>
override로 재정의 확인한다면 재정의 된 메서드로 실행됨
덮어 쓰기는 각자 실행하는 경우 문제x
부모 클래스 참조로 실행하는 경우 문제o
4.추상(Abstract) 클래스와 메서드
직접적으로 인스턴스를 생성할 수 없는 클래스(두루뭉실함)
주로 상속을 위한 베이스 클래스로 사용된다.
추상 클래스는 abstarct를 키워드로 선언한다. 또한 추상 메서드를 포함할 수 있다.
추상 클래스는 선언만 하고 구현은 안한다.
구현은 누가함? ==> 상속받은 메서드가 '무조건' 구현해야함
abstract는 override(재정의)에 강제성이 더해짐
virtual과 비슷하지만
virtual은 자식 클래스의 재정의가 있기도, 없기도 하지만
abstract 무조건 override가 존재한다는 점이 다르다.
5.오버라이딩 과 오버로딩
오버라이딩(Overriding) : 부모클래스에 이미 정의된 메소드를 자식이 재정의 한다
이때, 오버라이딩 하는 클래스들은 상속 관계에 있어야 하며, 메서드 이름,
매개변수 및 반환타입이 동일해야 한다
덮어 쓸 때 씀
오버로딩(OverLoading) : 같은 이름의 메서드가 여러개 있는것
매개변수의 타입, 개수, 순서가 달라지는만큼 생긴다.
읽어 올 때 씀