본문 바로가기

C#

C# 다형성 (override, overload, implicit, explicit)

반응형

C# 다형성

메서드 오버라이드

- 자식클래스에서 부모클래스로부터 상속받은 부모의 메서드를 재정의하여 사용하는 것

1. 부모클래스에서는 오버라이드를 가능하게 하기 위해 'virtual' 이라는 예약어를 메서드 앞에 붙인다.

2. 자식클래스에서는 재정의하여 사용하고 싶으면 'override' 라는 예약어를 메서드 앞에 붙인다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace ConsoleApp2
{
    class Mammal
    {
        virtual public void Move()
        {
            Console.WriteLine("이동한다");
        }
    }
    class Whale : Mammal
    {
        public override void Move()
        {
            Console.WriteLine("수영한다");
        }
    }
    class Human : Mammal
    {
        public override void Move()
        {
            Console.WriteLine("두발로 걷는다");
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
          //생략
        }
    }
    
}
 


* 자식클래스에서 부모클래스와 동일한 이름의 메서드를 정의하고 싶은 경우도 있다. (재정의아님)

그럴땐 메서드앞에 new를 붙임 (부모와 자식 둘다)

1. 오버라이드를 원한다? virtual / override 사용

2. 그냥 자식클래스에서 동일한 이름의 메서드를 쓰고싶다? / new 사용


base

자바의 super 처럼 오버라이드할 때 자식클래스의 메서드에서 부모의 메서드에 접근할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Computer
{
    virtual public void Boot()
    {
        Console.WriteLine("부트");
    }
}
class Notebook : Computer
{
    public override void Boot()
    {
       base.Boot();
        Console.WriteLine("액정키기");
    }
}


//결과

//부트

//액정키기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Book
{
    string title;
    decimal isbn13;
    string author;
        
    public Book(string title,decimal isbn13, string author)
    {
        this.title = title;
        this.isbn13 = isbn13;
        this.author = author;
    }
 
    public override bool Equals(object obj)
    {
        if(obj == null)
        {
            return false;
        }
        Book book = obj as Book;
        if(book == null)
        {
            return false;
        }
        return this.isbn13 == book.isbn13;
    }
    public override int getHashCode()
    {
        return this.isbn13.GetHashCode();
    }
}


Equals() 를 오버라이드해서 해당 객체간에 비교할 수 있다.

Book 클래스의 고유키(key)를 이용하여 같은지 다른지 비교하는 코드

getHashCode() 메서드 역시 키값의 이용해 같은 객체는 같은 해시코드를 반환한다는 룰을 만듦


메서드 오버로드

다중 생성자와 유사하게 어떤 클래스내에서 메서드가 이름은 똑같지만 매개변수 개수나 타입, 리턴 타입이 다른 메서드를 여러개 정의하여 일관성있게 메서드를 작성하는 법

1
2
3
4
5
6
7
8
9
10
11
12
public int Abs(int value)
{
    return (value >= 0) ? value : -value;
}
public double Abs(double value)
{
    return (value >= 0) ? value : -value;
}
public decimal Abs(decimal value)
{
    return (value >= 0) ? value : -value;
}
cs

이렇게 정의하고 Abs(-5) = 5, Abs(-10.02); = 10.02 이런식으로 사용

연산자 오버로드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class kilogram
{
    double mass;
    public kilogram(double value)
    {
        this.mass = value;
    }
    public static kilogram operator +(kilogram op1, kilogram op2)
    {
        return new kilogram(op1.mass + op2.mass);
    }
}
class Program
{
    static void Main(string[] args)
    {
            kilogram kg1 = new kilogram(5);
            kilogram kg2 = new kilogram(10);
            kilogram kg3 = kg1 + kg2;
    }
}
cs

public static 타입 operator 연산자(타입 변수명, 타입 변수명){ }

이런식으로 static 과 operator 키워드 사용.

결과적으로 객체간의 + 연산이 가능해졌다.

* 모든 연산자를 재정의 할 수 있는 것은 아니기때문에 확인하고 사용.

***** 형변환 연산자 오버로딩

"단위"를 사용하는 프로그램에서 유용함.

1
2
3
4
5
decimal won = 30000;
decimal dollar = won * 1200;
decimal yen = won * 13;
 
yen = dollar; // 이렇게 해도 컴파일 오류 없음.
cs

굉장히 위험한 코드지만 오류를 잡지 못하므로 이럴 때 오류로 잡을 수 있게할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace ConsoleApp2
{
    public class Currency
    {
        decimal money;
        public decimal Money { get { return money; } }
        public Currency(decimal money)
        {
            this.money = money;
        }
    }
    public class Won : Currency
    {
        public Won(decimal money) : base(money) { }
        public override string ToString()
        {
            return Money + "Won";
        }
    }
    public class Dollar : Currency
    {
        public Dollar(decimal money) : base(money) { }
        public override string ToString()
        {
            return Money + "Dollar";
        }
    }
    public class Yen : Currency
    {
        public Yen(decimal money) : base(money) { }
        public override string ToString()
        {
            return Money + "Yen";
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Won won = new Won(1000);
            Dollar dollar = new Dollar(1);
            Yen yen = new Yen(13);
            won = yen; // 타입이 다르므로 컴파일때 오류를 줌
        }
    }
    
}
 


사고를 방지했다.

하지만 때로는 Won과 Yen 사이의 형변환이 가능하길 바랄수도 있다. 일정한 환율에 따라 정의하려면 explict, implicit 연산자를 사용하면 된다.

1
2
3
4
static public implicit operator Won(Yen yen)
{
    return new Won(yen.Money * 13m); // 1yen당 13원으로 책정
}
cs

implicit 연산자를 오버로드 했으므로 암시적 형변환 가능

1
2
3
4
Yen yen = new Yen(100);
 
Won won1 = yen; //암시적 형변환
Won won2 = (Won)yen; // 명시적 형변환


민감한 통화 단위에 대해 암시적 형변환을 허용하는 것은 좋지 않다고 판단한다면

implicit 대신 explicit으로 구현하면 된다. 이렇게 구현하면 반드시 명시적 형변환만 써야한다.

반응형