1. 파생 클래스 (Derived Class)
- 상속(Inheritance): 상속은 베이스 클래스의 모든 멤버를 파생 클래스로 전달하여, 코드의 재사용성을 높이는 기능입니다. C#에서는 단일 상속만 지원하며, 하나의 베이스 클래스로부터만 상속할 수 있습니다.
파생 클래스의 정의 예시:
class BaseClass {
int a;
void MethodA() {
// ...
}
}
class DerivedClass : BaseClass {
int b;
void MethodB() {
// ...
}
}
base 지정어: 베이스 클래스의 생성자나 메소드를 호출할 때 base
키워드를 사용합니다.
만약 상속받은 클래스의 값을 사용하고 싶다면 base.a 이런식으로 사용하면된다.
예시1 - base 키워드를 사용한 생성자 호출 예시
using System;
// 부모 클래스
class Animal {
public string Name { get; set; }
// 부모 클래스의 생성자
public Animal(string name) {
Name = name;
Console.WriteLine($"Animal 생성자 호출: {Name}");
}
}
// 자식 클래스
class Dog : Animal {
public string Breed { get; set; }
// 파생 클래스의 생성자에서 base를 사용해 부모 생성자 호출
public Dog(string name, string breed) : base(name) {
Breed = breed;
Console.WriteLine($"Dog 생성자 호출: {Breed}");
}
}
class Program {
static void Main() {
Dog myDog = new Dog("Buddy", "Golden Retriever");
}
}
예시2 - base 키워드를 사용한 메서드 호출 예시
using System;
// 부모 클래스
class Animal {
public virtual void Speak() {
Console.WriteLine("Animal is making a sound.");
}
}
// 자식 클래스
class Dog : Animal {
// 부모 클래스의 메서드를 재정의
public override void Speak() {
base.Speak(); // 부모 클래스의 Speak 메서드 호출
Console.WriteLine("Dog is barking!");
}
}
class Program {
static void Main() {
Dog myDog = new Dog();
myDog.Speak();
}
}
2. 메소드 재정의 (Method Overriding)
- 메소드 재정의는 베이스 클래스에서 정의된 메소드를 파생 클래스에서 재정의하는 것입니다. 메소드 시그니처가 동일해야 재정의가 가능합니다.
- 메소드를 재정의하려면
override
키워드를 사용합니다.
예시:
class BaseClass {
public virtual void Print() {
Console.WriteLine("Base Print Method");
}
}
class DerivedClass : BaseClass {
public override void Print() {
Console.WriteLine("Derived Print Method");
}
}
3. 가상 메소드와 봉인 메소드
- 가상 메소드(virtual method):
virtual
로 선언된 메소드는 파생 클래스에서 재정의할 수 있습니다.- 기본 클래스에서 정의된 메소드나 프로퍼티를 파생 클래스에서 재정의할 수 있도록 허용
- 기본 클래스에서 virtual 키워드로 선언된 메소드는 파생 클래스에서 override 키워드를 사용하여 재정의할 수 있습니다.
- override를 작성하지 않으면 재정의가 되지 않는다.
using System;
// 부모 클래스
class Animal {
public string Name { get; set; }
// virtual 키워드를 사용하여 재정의 가능하도록 설정
public virtual void Speak() {
Console.WriteLine("Animal is making a sound.");
}
}
// 자식 클래스
class Dog : Animal {
// override 키워드를 사용하여 부모의 Speak 메서드를 재정의
public override void Speak() {
Console.WriteLine($"{Name} is barking!");
}
}
class Program {
static void Main() {
// Dog 객체 생성
Dog myDog = new Dog();
myDog.Name = "Buddy";
myDog.Speak(); // 출력: Buddy is barking!
// 부모 클래스의 Speak 호출
Animal myAnimal = new Animal();
myAnimal.Name = "Some animal";
myAnimal.Speak(); // 출력: Animal is making a sound.
}
}
- 봉인 메소드(sealed method):
sealed
로 선언된 메소드는 더 이상 파생 클래스에서 재정의할 수 없습니다.- 재정의를 허용하지 않는다.
4. 추상 클래스 (Abstract Class)
- 추상 클래스는 실질적인 구현을 제공하지 않는 추상 메소드를 포함하는 클래스입니다. 이러한 추상 메소드는 파생 클래스에서 반드시 구현해야 합니다.
- 추상 메소드는
abstract
키워드를 사용하여 선언하며, 추상 클래스는 직접 인스턴스를 만들 수 없습니다.
추상 클래스 예시:
abstract class AbstractClass {
public abstract void AbstractMethod();
public void NormalMethod() {
Console.WriteLine("Normal method in abstract class");
}
}
class ConcreteClass : AbstractClass {
public override void AbstractMethod() {
Console.WriteLine("Abstract method implemented");
}
}
5. 클래스형 변환 (Casting)
- 상향식 캐스트(Upcasting): 파생 클래스 객체를 베이스 클래스 형식으로 변환하는 것은 가능합니다.
- 하향식 캐스트(Downcasting): 베이스 클래스 객체를 파생 클래스 형식으로 변환하는 것은 명시적인 캐스트가 필요하며, 경우에 따라 예외가 발생할 수 있습니다.
클래스형 변환 예시:
BaseClass obj = new DerivedClass(); // 상향식 캐스트 (자동)
DerivedClass derivedObj = (DerivedClass)obj; // 하향식 캐스트 (명시적)
상속 관계에서의 클래스 형변환은 기본 클래스(부모 클래스, base)와 파생 클래스(자식 클래스) 간에 업캐스팅(Upcasting)과 다운캐스팅(Downcasting)을 통해 가능합니다. 각각의 변환은 특정 규칙에 따라 가능하거나 제한됩니다.
1. 업캐스팅(Upcasting): 파생 클래스에서 기본 클래스로 변환
- 업캐스팅(Upcasting)은 파생 클래스의 객체를 기본 클래스 타입으로 변환하는 것입니다.
- 항상 안전하며, 명시적 캐스팅 없이도 가능합니다.
- 상속 관계에서 파생 클래스는 기본 클래스의 모든 멤버를 상속받기 때문에, 파생 클래스 객체를 기본 클래스 타입으로 변환할 때 데이터 손실이 발생하지 않습니다.
업캐스팅 예시:
class BaseClass {
public void Show() {
Console.WriteLine("Base class method");
}
}
class DerivedClass : BaseClass {
public void Display() {
Console.WriteLine("Derived class method");
}
}
class Program {
public static void Main() {
DerivedClass derived = new DerivedClass();
// 업캐스팅: 파생 클래스의 객체를 기본 클래스 타입으로 변환
BaseClass baseObj = derived;
baseObj.Show(); // Base class method 출력
// baseObj.Display(); // 오류: BaseClass에는 Display() 메소드가 없음
}
}
설명:
- 업캐스팅을 통해
DerivedClass
객체를BaseClass
타입으로 변환합니다. - 업캐스팅 후에는 기본 클래스의 멤버들만 사용할 수 있습니다. 파생 클래스에서 추가된 메소드나 속성(
Display()
같은)은 기본 클래스 타입으로 변환된 후에는 접근할 수 없습니다.
2. 다운캐스팅(Downcasting): 기본 클래스에서 파생 클래스로 변환 -> 🚨"예외 발생"🚨
- 다운캐스팅(Downcasting)은 기본 클래스의 객체를 파생 클래스 타입으로 변환하는 것입니다.
- 다운캐스팅은 안전하지 않을 수 있으며, 명시적 캐스팅이 필요합니다.
- 기본 클래스의 객체가 실제로 파생 클래스의 객체인 경우에만 다운캐스팅이 성공합니다. 그렇지 않으면
InvalidCastException
예외가 발생합니다.
다운캐스팅 예시:
class BaseClass {
public void Show() {
Console.WriteLine("Base class method");
}
}
class DerivedClass : BaseClass {
public void Display() {
Console.WriteLine("Derived class method");
}
}
class Program {
public static void Main() {
BaseClass baseObj = new DerivedClass(); // 업캐스팅
baseObj.Show(); // Base class method 출력
// 다운캐스팅: BaseClass 객체를 DerivedClass 타입으로 변환
DerivedClass derivedObj = (DerivedClass)baseObj; // 명시적 캐스팅
derivedObj.Display(); // Derived class method 출력
}
}
설명:
BaseClass
객체가 실제로DerivedClass
객체로 생성된 경우에만 다운캐스팅이 성공합니다.BaseClass
타입에서 다시DerivedClass
타입으로 변환한 후에는 파생 클래스의 멤버(Display()
)를 호출할 수 있습니다.
3. 다운캐스팅의 위험성과 as
키워드
다운캐스팅이 성공하려면, 기본 클래스 객체가 실제로 파생 클래스 객체여야 합니다. 그렇지 않으면 InvalidCastException
이 발생할 수 있습니다. 이를 방지하기 위해 as
키워드 또는 is
키워드를 사용할 수 있습니다.
as
키워드를 사용한 안전한 다운캐스팅:
BaseClass baseObj = new BaseClass();
DerivedClass derivedObj = baseObj as DerivedClass;
if (derivedObj != null) {
derivedObj.Display();
} else {
Console.WriteLine("다운캐스팅에 실패했습니다.");
}
설명:
as
키워드를 사용하면 다운캐스팅이 실패할 경우 예외를 발생시키지 않고, 대신null
을 반환합니다. 이를 통해 다운캐스팅이 실패했을 때의 처리를 할 수 있습니다.
4. 업캐스팅과 다운캐스팅의 차이점 요약
캐스팅 종류 | 설명 | 명시적 캐스팅 필요 여부 | 안전성 |
---|---|---|---|
업캐스팅(Upcasting) | 파생 클래스 객체를 기본 클래스 타입으로 변환. 항상 안전하며 명시적 캐스팅이 필요 없음. | 필요 없음 | 안전함 |
다운캐스팅(Downcasting) | 기본 클래스 객체를 파생 클래스 타입으로 변환. 명시적 캐스팅 필요. 실제로 파생 클래스 객체일 경우에만 성공하며, 실패 시 예외 발생 가능. | 필요 | 안전하지 않음. 실패 시 예외 발생 가능 |
5. 정리
- 업캐스팅(파생 클래스 → 기본 클래스)은 항상 안전하며, 명시적인 캐스팅이 필요하지 않습니다. 기본 클래스는 파생 클래스에서 상속받은 모든 멤버를 포함하므로, 파생 클래스를 기본 클래스 타입으로 변환하는 것은 문제가 없습니다.
- 다운캐스팅(기본 클래스 → 파생 클래스)은 안전하지 않을 수 있으며, 명시적 캐스팅이 필요합니다. 다운캐스팅하려는 객체가 실제로 파생 클래스의 객체일 때만 성공하며, 그렇지 않으면 예외가 발생할 수 있습니다.
6. 다형성 (Polymorphism)
- 다형성은 객체의 실제 형식에 따라 메소드 호출이 달라지는 특성을 말합니다. C#에서는 virtual과 override 키워드를 통해 구현됩니다. 다형성을 통해 동일한 인터페이스로 다양한 객체를 처리할 수 있습니다.
다형성 예시:
BaseClass obj = new DerivedClass();
obj.Print(); // DerivedClass의 Print 메소드가 호출됨
'2학년 2학기 > 윈도우즈 프로그래밍' 카테고리의 다른 글
고급 프로그래밍 기법(1) - 제너릭, Attribute (0) | 2024.09.30 |
---|---|
인터페이스(2) - 인터페이스, 다중상속 (0) | 2024.09.30 |
클래스(2) - 메소드 / 연산자 오버로딩, 생성자, 인덱서, 프로퍼티 (0) | 2024.09.30 |
클래스(1) - 클래스 선언, 생성, 필드, 메소드 (0) | 2024.09.30 |
필드와 프로퍼티의 차이 (0) | 2024.09.30 |