Search

이것이 C#이다: 7장 - 클래스 (2/3)

1. 상속으로 코드 재활용하기

상속은 객체 지향 프로그래밍의 가장 중요한 특성 중 하나입니다. C#에서 상속을 통해 기존 클래스의 기능을 확장하거나 수정할 수 있습니다.

1.1 상속의 기본 개념

파생 클래스는 기반 클래스의 모든 멤버를 상속받아 사용할 수 있습니다.
public class Animal { public void Eat() { Console.WriteLine("Eating..."); } } public class Dog : Animal { public void Bark() { Console.WriteLine("Barking..."); } }
C#
복사
이 예제에서 Dog 클래스는 Animal 클래스를 상속받아 Eat() 메소드를 사용할 수 있습니다.

1.2 생성자와 소멸자의 호출 순서

파생 클래스의 객체가 생성될 때, 기반 클래스의 생성자가 먼저 호출된 후 파생 클래스의 생성자가 호출됩니다. 소멸 시에는 이 순서가 반대로 됩니다.
public class Base { public Base() { Console.WriteLine("Base Constructor"); } ~Base() { Console.WriteLine("Base Destructor"); } } public class Derived : Base { public Derived() { Console.WriteLine("Derived Constructor"); } ~Derived() { Console.WriteLine("Derived Destructor"); } }
C#
복사
이 코드를 실행하면 다음과 같은 순서로 출력됩니다:
1.
기반 클래스의 생성자 → 파생 클래스의 생성자
2.
파생 클래스의 소멸자 → 기반 클래스의 소멸자

1.3 base 키워드 활용

base 키워드를 사용하면 파생 클래스에서 기반 클래스의 멤버에 접근할 수 있습니다. 특히 생성자에서 유용하게 사용됩니다.
public class Animal { protected string name; public Animal(string name) { this.name = name; } } public class Dog : Animal { public Dog(string name) : base(name) { } public void Introduce() { Console.WriteLine($"I'm {name}"); } }
C#
복사
여기서 Dog 클래스의 생성자는 base(name)을 통해 Animal 클래스의 생성자를 호출합니다.

1.4 상속 봉인하기

sealed 키워드를 사용하면 클래스가 더 이상 상속되지 않도록 할 수 있습니다.
public sealed class FinalClass { // 이 클래스는 상속될 수 없습니다. }
C#
복사

2. 기반 클래스와 파생 클래스 사이의 형식 변환

C#에서는 리스코프 치환 원칙에 따라 파생 클래스의 인스턴스를 기반 클래스의 인스턴스로 취급할 수 있습니다.

2.1 형식 변환 연산자

C#은 isas 두 가지 형식 변환 연산자를 제공합니다.
1.
is 연산자: 객체가 특정 형식에 해당하는지 검사
2.
as 연산자: 형식 변환을 시도하며, 실패 시 null 반환
Animal myPet = new Dog(); if (myPet is Dog) { Dog myDog = (Dog)myPet; myDog.Bark(); } Dog anotherDog = myPet as Dog; if (anotherDog != null) { anotherDog.Bark(); }
C#
복사
as 연산자는 예외를 발생시키지 않아 안전한 형식 변환에 적합하지만, 값 형식에는 사용할 수 없다는 점을 유의해야 합니다.

3. 오버라이딩과 다형성

메소드 오버라이딩은 다형성을 구현하는 핵심 메커니즘입니다. C#에서 메소드를 오버라이딩하려면 다음 조건을 만족해야 합니다:
1.
기반 클래스의 메소드가 virtual 키워드로 선언되어 있어야 함
2.
파생 클래스에서 override 키워드를 사용하여 메소드를 재정의

3.1 virtual과 override 키워드

기반 클래스에서 virtual 키워드로 선언된 메소드는 파생 클래스에서 override 키워드를 사용해 재정의할 수 있습니다.
public class Shape { public virtual void Draw() { Console.WriteLine("Drawing a shape"); } } public class Circle : Shape { public override void Draw() { Console.WriteLine("Drawing a circle"); } }
C#
복사
이렇게 하면 Circle 객체의 Draw 메소드를 호출할 때 "Drawing a circle"이 출력됩니다.

4. 메소드 숨기기

메소드 숨기기는 오버라이딩과 유사하지만, 다형성을 구현하지 않습니다. 대신, 파생 클래스에서 기반 클래스의 메소드를 '가리는' 효과를 냅니다.
public class Base { public void Method() { Console.WriteLine("Base Method"); } } public class Derived : Base { public new void Method() { Console.WriteLine("Derived Method"); } }
C#
복사
이 경우, Derived 객체의 Method를 호출하면 "Derived Method"가 출력되지만, 이 객체를 Base 타입으로 캐스팅하면 "Base Method"가 출력됩니다.

5. 오버라이딩 봉인하기

sealed 키워드를 사용하여 파생 클래스에서 더 이상 오버라이딩할 수 없도록 메소드를 봉인할 수 있습니다.
public class Base { public virtual void Method() { } } public class Derived : Base { public sealed override void Method() { } }
C#
복사

6. 읽기 전용 필드

readonly 키워드를 사용하여 읽기 전용 필드를 선언할 수 있습니다. 이는 상수와 변수의 중간 형태로, 생성자에서만 값을 할당할 수 있습니다.
public class MyClass { public readonly int MyReadOnlyField; public MyClass(int value) { MyReadOnlyField = value; // 생성자에서만 값 할당 가능 } }
C#
복사

참고 자료

박상현, "이것이 C#이다", 한빛미디어, 2023