C# 상속 마스터하기: 재사용 가능하고 유지보수하기 쉬운 코드 작성
객체 지향 프로그래밍에서 가장 중요한 개념 중 하나는 상속(Inheritance)입니다. 상속을 사용하면 기존 클래스를 기반으로 새 클래스를 정의할 수 있어, 애플리케이션 생성과 유지보수가 쉬워집니다. 코드 기능 재사용이 가능하고 구현 시간이 단축됩니다.
새 클래스를 만들 때 완전히 새로운 멤버를 작성하는 대신, 기존 클래스의 멤버를 물려받도록 지정할 수 있습니다. 기존 클래스를 기본 클래스(Base Class), 새 클래스를 파생 클래스(Derived Class)라고 합니다.
상속은 IS-A 관계를 구현합니다. 예: 포유류 IS-A 동물, 개 IS-A 포유류 → 개 IS-A 동물.
기본 클래스와 파생 클래스
한 클래스는 여러 클래스나 인터페이스에서 파생될 수 있습니다 (다중 구현 상속은 인터페이스로).
<접근_지정자> class <기본_클래스> { ... }
class <파생_클래스> : <기본_클래스> { ... }
예제: Shape 기본 클래스와 Rectangle 파생 클래스
using System;
namespace InheritanceApplication
{
class Shape
{
public void SetWidth(int w) { width = w; }
public void SetHeight(int h) { height = h; }
protected int width; // 파생 클래스에서 접근 가능
protected int height;
}
// 파생 클래스
class Rectangle : Shape
{
public int GetArea() { return width * height; }
}
class RectangleTester
{
static void Main(string[] args)
{
Rectangle rect = new Rectangle();
rect.SetWidth(5);
rect.SetHeight(7);
Console.WriteLine("총 면적: {0}", rect.GetArea()); // 35
Console.ReadKey();
}
}
}
기본 클래스 초기화
파생 클래스는 기본 클래스 멤버를 물려받으므로, 서브클래스 생성 전 슈퍼클래스 객체가 먼저 생성되어야 합니다. 멤버 초기화 리스트에서 기본 클래스 초기화 지시를 할 수 있습니다.
생성자 체이닝 예제: Tabletop이 Rectangle 상속
using System;
namespace RectangleApplication
{
class Rectangle
{
protected double length;
protected double width;
public Rectangle(double l, double w) // 기본 클래스 생성자
{
length = l; width = w;
}
public double GetArea() { return length * width; }
public void Display()
{
Console.WriteLine("Length: {0}", length);
Console.WriteLine("Width: {0}", width);
Console.WriteLine("Area: {0}", GetArea());
}
}
class Tabletop : Rectangle
{
private double cost;
// base(l, w)로 기본 클래스 생성자 호출
public Tabletop(double l, double w) : base(l, w) { }
public double GetCost()
{
return GetArea() * 70;
}
public void Display()
{
base.Display(); // 기본 클래스 Display 호출
Console.WriteLine("Cost: {0}", GetCost());
}
}
class ExecuteRectangle
{
static void Main(string[] args)
{
Tabletop t = new Tabletop(4.5, 7.5);
t.Display();
Console.ReadLine();
}
}
}
출력: Length: 4.5, Width: 7.5, Area: 33.75, Cost: 2362.5
C#의 다중 상속
C#은 다중 구현 상속을 지원하지 않습니다. 하지만 인터페이스를 사용하여 다중 상속 효과를 낼 수 있습니다.
인터페이스로 다중 상속 구현
using System;
namespace InheritanceApplication
{
class Shape
{
public void SetWidth(int w) { width = w; }
public void SetHeight(int h) { height = h; }
protected int width, height;
}
// 인터페이스 (페인트 비용 계약)
public interface IPaintCost
{
int GetCost(int area);
}
// Shape 상속 + IPaintCost 구현
class Rectangle : Shape, IPaintCost
{
public int GetArea() { return width * height; }
public int GetCost(int area) { return area * 70; }
}
class RectangleTester
{
static void Main(string[] args)
{
Rectangle rect = new Rectangle();
rect.SetWidth(5);
rect.SetHeight(7);
int area = rect.GetArea();
Console.WriteLine("총 면적: {0}", area); // 35
Console.WriteLine("총 페인트 비용: ${0}", rect.GetCost(area)); // 2450
Console.ReadKey();
}
}
}
상속 관련 핵심 키워드
| 키워드 | 설명 |
base | 기본 클래스 멤버 접근 (생성자, 메서드, 필드) |
virtual | 파생 클래스에서 오버라이드 가능한 메서드 표시 |
override | 기본 클래스의 virtual/abstract 메서드 재정의 |
sealed | 클래스/메서드 상속/오버라이드 금지 |
abstract | 구현 없는 메서드/클래스, 파생 클래스에서 구현 필수 |
protected | 파생 클래스에서만 접근 가능한 접근 지정자 |
설계 원칙: "상속보다 조합(Composition)을 선호하라"는 원칙을 기억하세요. IS-A 관계가 명확할 때만 상속을 사용하고, 코드 재사용이 주 목적이라면 인터페이스나 조합을 고려하세요.