C#/C# 교과서

[C# 교과서] 44~45. 메서드 오버라이드, 인터페이스

서니션 2023. 1. 30. 22:17
728x90
반응형

메서드 오버라이드 : 재정의

클래스 관계를 따지는 상속 개념에서 부모 클래스에 이미 만든 메서드를 동일한 이름으로 자식 클래스에서 다시 정의(재정의)해서 사용한다는 개념이 메서드 오버라이드

  • 메서드 오버라이드는 메서드를 새롭게 정의하는 것
  • 오버라이드, 오버라이딩이라는 표현은 동일
  • 부모 클래스에 virtual 키워드로 선언해 놓은 메서드는 자식 클래스에서 override 키워드로 재정의해서 사용 가능

상속 관계에서 메서드 오버라이드

public class Parent
{
	public void Say() => Console.WriteLine("부모_안녕하세요");
	public void Run() => Console.WriteLine("부모_달리다");
	public virtual void Walk() => Console.WriteLine("부모_걷다");
}

public class Child : Parent
{
	public void Say() => Console.WriteLine("자식_안녕하세요");
	public new void Run() => Console.WriteLine("자식_달리다");
	public override void Walk() => Console.WriteLine("자식_걷다");
}

Child c = new Child(); // 메서드 오버라이드 : 함수 재정의
c.Say(); // 재사용
c.Run(); // x->new
c.Walk(); // virtual -> override

Say() 메서드는 이렇게 작성해도 문제는 없지만 new를 쓰라고 경고 문구가 나옴

Run() 메서드는 new 키워드로 명확하게 재정의하여 사용함

Walk() 메서드는 부모 클래스에서 상속해서 사용해도 된다는 의미. virtual을 붙이고 자식 클래스에서는 재정의해서 쓰겠다는 의미로, override를 붙여 재정의하는 가장 좋은 형태의 코드를 볼 수 있음


메서드 오버로드와 오버라이드

오버로드 : 여러번 정의 하는 것

오버라이드 : 다시 정의(재정의)하는 것


가상 메서드

부모 클래스의 메서드에 virtual 키워드가 붙으면 자식 클래스에는 해당 메서드를 그대로 물려 받아 사용하거나 override 키워드를 붙여 새롭게 다시 만들어 사용할 수 있도록 규칙을 정할 수 있음


메서드 오버라이드 봉인

메서드에도 sealed 키워드를 붙여 더 이상 오버라이드해서 사용하지 못하도록 설정 가능

class Parent
{
	public virtual void Work() => Console.WriteLine("프로그래머");
}

class Child : Parent
{
	public override sealed void Work() => base.Work();
}

/* 자식 클래스에는 override 키워드로 부모의 Work() 메서드를 재정의하지만,
sealed 키워드를 붙여 Child 클래스의 Work() 메서드는 더 이상 오버라이드가 불가능하게 설정*/

ToString() 메서드 오버라이드

  • Object 클래스에 정의된 ToString() 메서드는 기본적으로 클래스의 이름 값을 반환
  • 정수형처럼 대표되는 값이 들어 있을 때는 그 값을 문자열로 변환해서 출력
  • 자신이 만든 클래스의 대표되는 속성 또는 값을 외부에 인스턴스 이름으로 출력할 때는 ToString() 메서드를 재정의해서 사용해야 함
using System;

namespace ClassToString
{
	class Person
	{
		private string name;
		
		public Person(string name)
		{
			this.name = name;
		}

		public override string ToString() => $"[Person 클래스 : {this.name}]";
	}

	class ClassToString
	{
		static void Main()
		{
			Person person = new Person("박용준");
			Console.WriteLine(person); // 개체를 문자열로 출력하면 ToString()이 호출됨
		}
	}
}

// 실행결과
// [Person 클래스 : 박용준]

인터페이스

클래스 또는 구조체에 포함될 수 있는 (관련 있는) 메서드들을 묶어 관리

  • interface 키워드를 사용하여 만듦. 실행 가능한 코드와 데이터 불포함
  • 추상 클래스처럼 다른 클래스에 멤버 이름을 미리 정의할 대 사용. 추상 클래스와 다른 점은 멤버 내용을 구현하지 않고 멤버 이름만 정의
  • 인터페이스에는 메서드, 속성, 인덱서 및 이벤트 정의 가능
  • 현실 세계에서 전 세계 표준과 같은 기능
  • 단일 상속만 지원하는 클래스와 달리 인터페이스를 사용한 다중 상속이 가능
  • 인터페이스 멤버는 액세스 한정자를 붙이지 않으며 항상 public이고, virtual 및 static을 붙일 수 없음
  • 인터페이스 내의 모든 멤버는 기본적으로 public
  • C#에서 인터페이스 이름은 ICar, IFood, IComputer 형태로 대문자 I로 시작함
  • 인터페이스는 인스턴스화되지 않음. 클래스를 사용해서 인스턴스화 됨
    • I인터페이스 i = new 클래스();
  • 인터페이스는 계약 의미가 강하며 속성, 메서드, 이벤트, 인덱서 등 구조를 미리 정의

인터페이스로 특정 멤버가 반드시 구현되어야 함을 보증

using System;

namespace InterfaceNote
{
	interface ICar
	{
		void Go();
	}

	class Car : ICar
	{
		public void Go() => Console.WriteLine("상속한 인터페이스에 정의된 모든 멤버를 반드시 구현해야 함");
	}

	class InterfaceNote
	{
		static void Main()
		{
			var car = new Car();
			car.Go();
		}
	}
}

인터페이스 형식 개체에 인스턴스 담기

using System;

public interface IRepository
{
	void Get();
}

public class Repository : IRepository
{
	public void Get()
	{
		Console.WriteLine("Get() 메서드를 구현해야 함");
	}
}

class InterfacePractice
{
	static void Main()
	{
		// 인터페이스 형식 개체에 인스턴스 담기
		IRepository repository = new Repository();
		repository.Get();
	}
}

인터페이스를 사용한 다중 상속 구현

C#에서 클래스는 클래스에 대한 단일 상속만 지원하는 대신, 인터페이스는 클래스에 인터페이스를 하나 이상 상속할 수 있음

using System;

namespace InterfaceInheritance
{
	interface IAnimal
	{ void Eat(); }
	interface IDog
	{ void Yelp(); }

	class Dog : IAnimal, IDog // 인터페이스를 사용한 다중 상속
	{
		public void Eat() => Console.WriteLine("먹다");
		public void Yelp() => Console.WriteLine("짖다");
	}

	class InterfaceInheritance
	{
		static void Main()
		{
			Dog dog = new Dog();
			dog.Eat();
			dog.Yelp();
		}
	}
}

// 실행결과
// 먹다
// 짖다

명시적인 인터페이스 구현

인터페이스를 사용한 다중 상속이 가능하기에 각 인터페이스에 동일한 멤버가 구현되어 있을 때 어떤 인터페이스의 멤버를 실행할지 지정해야 함

using System;

namespace InterfaceInheritance
{
	interface ICat
	{ void Eat(); }
	interface IDog
	{ void Eat(); }

	class Pet : ICat, IDog // 인터페이스를 사용한 다중 상속
	{
		void ICat.Eat() => Console.WriteLine("Cat Eat");
		void IDog.Eat() => Console.WriteLine("Dog Eat");
	}

	class InterfaceInheritance
	{
		static void Main()
		{
			Pet pet = new Pet();
			((ICat)pet).Eat();
			((IDog)pet).Eat();

			ICat cat = new Pet();
			cat.Eat();
			IDog dog = new Pet();
			dog.Eat();
		}
	}
}

// 실행결과
// 먹다
// 짖다

IDisposable 인터페이스 사용

이 메서드는 해당 클래스의 개체를 다 사용한 후 마지막으로 호출해서 정리하는 역할

using System;

class IDisposableDemo
{
	static void Main()
	{
		Console.WriteLine("[1] 열기");
		using (var t = new Toilet())
		{
			// 특정 프로세스를 종료하면 자동으로 닫기 수행
			Console.WriteLine("[2] 사용");
		}
	}
}

public class Toilet : IDisposable
{
	public void Dispose()
	{
		Console.WriteLine("[3] 닫기");
	}
}

using 문으로 개체를 묶어 생성하면 해당 using 문이 종료되면서 자동으로 Dispose() 메서드를 호출해서 정상 종료하도록 처리

728x90
반응형