오버라이딩
파생클래스에서 부모의 같은이름을 가진 메소드를 재정의하는것
부모메소드 - virtual로 수식
=> 메소드를 정의할때 부모메소드를 파생할 클래스가 부모의 구현에 한정되지 않도록 앞을 내다봐
virtual로 길을 열어준다
public virtual void Initialize() { // }
이렇게 virtual로 가상메소드를 선언한다. (추상메소드 abstact와 반대되는 개념)
파생메소드 - override로 수식
public override void Initialize() { // }
참고로, 오버라이드를 하지만, 부모의 유사를 버리고 싶지 않을 때
추가로 base키워드를 써서 base.Initialize(); 를 해주면 이는 파생에서 재정의한 메소드가 아닌
"부모" 의 Initialize()를 가져옴
public override void Initialize()
{
base.Initialize(); //부모의 initialize()
Console.WriteLine("..."); //오버라이딩 하며 추가한 구현
}
1학년 때 시험에 많이 나왔던 오버로딩과 오버라이딩의 차이
오버로딩은 이름은 같지만 시그니처(파라미터 수, 타입)는 다른 메소드를 중복으로 선언하는 것을 의미하고,
오버라이딩은 부모 클래스의 메소드 동작 방법을 변경(재정의)하여 우선적으로 사용하는 것이다
예제
using System;
using static System.Console;
namespace thistiscsharp
{
class Armor
{
public virtual void Initialized()
{
WriteLine("armored");
}
}
class IronMan : Armor
{
public override void Initialized()
//여기서 override만 빼고 실행시켜도 똑같이 출력되긴하는데
//부모와 같은 이름의 함수이므로
//경고문구로 override를 하거나 new를 쓰거나 하라고 뜸
{
base.Initialized();
WriteLine("ironman's Repulsor");
}
}
class WarMachine : Armor
{
public override void Initialized()
{
base.Initialized();
WriteLine("Warmachine's Cannons");
WriteLine("Warmachine's Launcher");
}
}
class MainClass
{
public static void Main(string[] args)
{
WriteLine("Creating Armor");
Armor armor = new Armor();
armor.Initialized();
WriteLine("");
WriteLine("Creating IronMan");
Armor ironman = new IronMan();
ironman.Initialized();
WriteLine("");
WriteLine("Creating WarMachine");
Armor warMachine = new WarMachine();
warMachine.Initialized();
WriteLine("");
}
}
}
메소드 숨기기(new)
- CLR에게 기반클래스에서 구현된 버전만 보여주는 것을 말한다
- 이 new는 생성자를 호출할 대 사용하는 new연사나와는 완전히 다름
- 기반클래스에서 메소드를 가상메소드(virtual)로 정의하지 않아도 new키워드를 붙이면
오버라이딩과 같은 효과를 얻을 수 잌ㅅ음
- 아래처럼 사용.
class Base
{
public void MyMethod()
{
Console.WriteLine("Base.MyMethod()");
}
}
class Dervied : Base
{
pulbic new void MyMethod()
{
Console.WrirteLine("Dervied.MyMethod()");
}
}
그럼 new만쓰면되는거아닌가? ㄴㄴ 오버라이딩과 다름. 메소드 숨기기는 말 그대로 메소드를 숨기고 있을 뿐
만약
Base baseOrDervied = new Dervied();
baseOrDervied.MyMethod(); // Base.MyMethod()출력
이런식으로 ( 부모형식 즉, Base형식인 참조변수 baseOrDervied로 파생클래스의 객체를 가리킨다)
객체를 생성하면 메소드숨기기는 baseOrDervied는 파생클래스의 메소드가 아닌, 부모클래스의 메소드를 호출한다
(부모의 MyMethod()가 숨겨져있다가 노출되어 실행되는것)
반면에, override를 사용하고 같은식으로 객체를 생성하면 파생클래스의 메소드를 호출한다
이처럼 메소드 숨기기는 완전한 다형성을 표현하지 못하는 한계가 있어서
기반클래스를 설계할때는 파생클래스의 모습까지 고려해야한다 = 웬만하면 virtual한정자를 붙인 오버라이딩 사용
using System;
using static System.Console;
namespace thistiscsharp
{
class Base
{
public virtual void MyMethod()
{
Console.WriteLine("Base.MyMethod()");
}
}
class Derived : Base
{
public new void MyMethod()
{
Console.WriteLine("Derived.MyMethod()");
}
}
class MainClass
{
public static void Main(string[] args)
{
Derived der = new Derived(); //의도한 대로 정상출력
der.MyMethod();
Base der2 = new Derived(); //new Derived로 객체 생성과 동시에 부모클래스로 바로 캐스팅하는
//이와 같은 코드의 업캐스팅을 하면 부모의 MyMethod()가 노출되어( 숨겨져있다가) 실행됨.
//기능상 오버라이드된 자식클래스의 MyMethod()가 실행되는게 아니라,
//바로 이게 오버라이딩과 메소드 숨기기가 다른 이유입니다! 메소드 숨기기는 이름 그대로 메소드를 숨기고 있을 뿐이에요
der2.MyMethod();
}
}
}
추가로
오버라이딩 봉인(sealed) - pg 267
public sealed override void SealMe() { // }
도 가능