본문 바로가기

Programming

상속 : 쉽고 재미있는 C# Programming 의 기본

 

상속성은 객체지향 프로그래밍 (OOP)의 중요한 특징 중 하나입니다.

 

상속성은 코드의 재사용성을 증가시키고 클래스 간의 계층 구조를 형성하여 코드의 구조를 조직화하는 데 사용됩니다.


 

1. 개념

 

상속 (Inheritance)은 객체지향 프로그래밍에서 사용디는 중요한 개념으로, 기존 클래스의 특성을 새로운 클래스가 물려받아 재사용하는 것을 의미합니다.

상속을 통해 새로은 클래스는 기존 클래스의 멤버 (필드, 메서드, 속성 등)를 그대로 또는 일부 수정하여 사용할 수 있습니다.

이로 인해 코드의 재사용성이 증가하며, 계층구조를 형성하여 객체의 관계를 명확하게 표현할 수 있습니다.

 

2. 상속의 구조

 

상속은 클래스 간의 부모-자식 관계를 형성합니다. 기본적인 상속 구조는 다음과 같습니다.

class ParentClass
{
    // 부모 클래스의 멤버들
}

class ChildClass : ParentClass
{
    // 자식 클래스의 추가 멤버들 또는 부모 클래스 멤버의 재정의
}

* ParentClass : 상속의 기반이 되는 부모 클래스입니다.

* ChildClass : ParentClass 를 상속받는 자식 클래스로, 부고 클래스의 멤버를 그대로 사용하거나 수정하여 새로운 기능을 추가합니다.

using System;

// 부모 클래스
class Animal
{
    public string Name { get; set; }

    public void Eat()
    {
        Console.WriteLine($"{Name} is eating.");
    }
}

// 자식 클래스
class Dog : Animal
{
    public void Bark()
    {
        Console.WriteLine($"{Name} is barking.");
    }
}

class Program
{
    static void Main()
    {
        // 자식 클래스의 객체 생성
        Dog myDog = new Dog();
        myDog.Name = "Buddy";

        // 부모 클래스의 메서드 호출
        myDog.Eat();   // Buddy is eating.

        // 자식 클래스의 메서드 호출
        myDog.Bark();  // Buddy is barking.
    }
}

 

위의 코드에서 Dog 클래스는 Animal 클래스를 상속받아 Name 속성과 Bark 메서드를 추가로 정의했습니다.

이렇게 하면 Dog 클래스는 Animal 클래스의 기능을 그대로 사용하면서 동시에 새로운 기능을 추가할 수 있습니다.

 

 

3. 상속의 활용

 

3.1 코드의 재사용성

class Animal
{
    public void Eat()
    {
        Console.WriteLine("Animal is eating.");
    }
}

class Dog : Animal
{
    // Dog 클래스는 Animal 클래스의 Eat 메서드를 그대로 상속받음
    public void Bark()
    {
        Console.WriteLine("Dog is barking.");
    }
}

// 사용 예시
Dog myDog = new Dog();
myDog.Eat();  // Animal is eating.
myDog.Bark(); // Dog is barking.

* Animal 클래스는 Eat 이라는 메서드를 정의하고 있습니다.

* Dog 클래스는 Animal 클래스를 상속받아 Eat 메서드를 그대로 사용하고, 추가로 Bark 메서드를 정의하였습니다.

* Dog 객체를 생성하여 Eat 메서드와 Bark 메서드를 호출할 수 있습니다.

 

이렇게 상속을 통해 Dog 클래스는 Animal 클래스의 기능을 확장하여 재사용하고 있습니다.

 

3.2 다형성 ( Polymorphism )

class Shape
{
    public virtual void Draw()
    {
        Console.WriteLine("Drawing a shape.");
    }
}

class Circle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a circle.");
    }
}

class Square : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a square.");
    }
}

// 다형성을 통한 사용 예시
Shape[] shapes = new Shape[] { new Circle(), new Square() };

foreach (Shape shape in shapes)
{
    shape.Draw();
}

* Shape 클래스는 Draw 라는 가상(Virtual) 메서드를 정의하고 있습니다.

* Circle 및 Square 클래스는 각각 Shape 클래스를 상속받아 Draw 메서드를 재정의하였습니다.

* 배열에 Circle 객체와 Square 객체를 담고, 반복문을 통해 각 객체의 Draw 메서드를 호출합니다.

* 가상메서드 (Virtual Method) 선언과 override는 다형성 편에서 상세히 설명합니다.

 

다형성을 통해 동일한 메서드 호출이 각 객체에서 다르게 작동하는 것을 확인할 수 있습니다.

 

3.3 추상 클래스와 인터페이스

// 추상 클래스
abstract class Shape
{
    public abstract void Draw(); // 추상 메서드
}

// 인터페이스
interface IDrawable
{
    void Draw();
}

class Circle : Shape, IDrawable
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a circle.");
    }
}

// 사용 예시
Circle circle = new Circle();
circle.Draw(); // Drawing a circle

* Shape 클래스는 추상클래스로서 Draw 라는 추상 메서드를 선언합니다.

* IDrawable 인터페이스는 Draw 메서드를 정의합니다.

* Cicle 클래스는 Shape 클래스를 상속받고, IDrawable 인터페이스를 구현하여 Draw 메서드를 재정의합니다.

* Circle 객체를 생성하고, Draw 메서드를 호출하여 다양한 형태의 추상화를 통한 설계를 확인할 수 있습니다.

 

상속을 통해 추상 클래스와 인터페이스를 구현하면, 다양한 클래스가 공통적으로 사용가능한 규약을 정의할 수 있습니다.


상속의 주요 목적 중 하나는 공통된 기능이나 속성을 부모 클래스에 정의하고, 이를 여러 자식 클래스에서 재사용하는 것입니다.

부모 클래스에 있는 특성은 자식 클래스에서 중복해서 구현할 필요가 없으며, 이로써 코드의 재사용성이 증가하고 유지보수가 편리해집니다.

 

기본적으로 부모 클래스에는 공통적인 특성이나 동작이 정의되며, 자식 클래스에서는 이를 상속받아 추가적인 기능을 구현하거나 기존 기능을 재정의할 수 있습니다.


 

이는 다음과 같은 이점을 제공합니다.

 

1. 코드의 재사용성

 

공통된 코드를 부모 클래스에 두면 각 자식 클래스에서 중복해서 작성하지 않아도 됩니다.

 

2. 유지보수 용이성

 

공통된 기능이 변경되어야 할 경우, 부모 클래스만 수정하면 됩니다.

이는 코드의 일관성을 유지하고 버기를 줄일 수 있습니다.

 

3. 계층 구조 형성

 

클래스 간의 계층 구조를 형성하여 객체의 관계를 명확하게 표현할 수 있습니다.

이는 설계를 이해하고 확장하기 쉽게 만듭니다.

 

4. 다형성 지원

 

상속을 통해 다형성을 구현할 수 있습니다. 동일한 메서드를 부모 클래스와 자식 클래스에서 다르게 구현함으로써 다양한 객체를 통일적으로 처리할 수 있습니다.

 

예를 들어, 동물 클래스가 있을 때, 포유류, 조류, 어류 등을 나타내는 각각의 동물 클래스를 만들어 동물의 특성을 상속하는 것이 효과적입니다. 이러한 클래스 구조는 공통된 동물의 특성을 부모 클래스에 두고, 각각의 동물에 특화된 기능을 자식 클래스에 추가할 수 있게 합니다.


 

상속(Inheritance) 을 이해하고 사용하기 위해서는 다음과 같은 주요 개념과 특징들을 이해해야 합니다.

 

1. 클래스 (Class)

 

클래스는 객체지향 프로그래밍에서 기본적인 개념입니다. 클래스는 속성(필드)과 동작(메서드)을 가지며, 객체를 생성하기 위한 틀이 됩니다.

 

2. 객체 (Object)

클래스의 인스턴스인 실제 데이터를 나타냅니다. 객체는 클래스의 속성과 메서드를 가지며, 클래스의 정의에 따라 동작합니다.

 

3. 가상 메서드 (Virtual Method)

 

virtual 키워드를 사용하여 선언된 메서드로, 자식 클래스에서 재정의할 수 있는 메서드입니다. 가상 메서드를 통해 다형성을 구현할 수 있습니다.

 

4. 추상 클래스 (Abstract Class)

 

abstract 키워드를 사용하여 선언된 클래스로, 하나 이상의 추상 메서드를 포함할 수 있습니다. 추상 메서드는 자식 클래스에서 반드시 구현되어야 합니다.

 

5. 인터페이스 (Interface)

 

interface 키워드를 사용하여 선언된 구조로, 메서드, 속성, 이벤트 등의 시그니처를 정의합니다. 여러 클래스에서 공통된 행동을 정의하기 위해 사용됩니다.

 

6. 다형성 (Polymorphism)

 

다형성은 같은 이름의 메서드나 속성이 여러 클래스에서 다르게 구현될 수 있는 능력을 말합니다. 상속을 통해 다형성을 구현할 수 있습니다.

 

7. 단일상속 (Single Inheritance)

C#에서는 하나의 클래스가 하나의 직계 부모 클래스만 상속할 수 있는 제한이 있습니다. 즉, 클래스 간의 단일 상속이 지원됩니다.

 

8. sealed 키워드

 

sealed 키워드는 클래스나 메서드를 상속이나 재정의에서 제외시키는 역할을 합니다.

Sealed 클래스는 더 이상 다른 클래스로부터 파생될 수 없으며, 다른 클래스에서 상속받을 수 없습니다. 이를 통해 특정 클래스의 구현을 완전히 제한하고, 그 클래스의 확장을 방지할 수 있습니다.

// Sealed 클래스 정의
sealed class SealedClass
{
    public void SomeMethod()
    {
        Console.WriteLine("This is a sealed class method.");
    }
}

// sealed 클래스를 상속받으려고 하면 컴파일 오류가 발생
// class DerivedClass : SealedClass { } // Error: cannot derive from sealed type 'SealedClass'

class Program
{
    static void Main()
    {
        SealedClass sealedObj = new SealedClass();
        sealedObj.SomeMethod();
    }
}

 

위의 예제에서 SealedClass는 sealed 키워드로 표시되었습니다.

이로 인해 다른 클래스가 SealedClass를 상속받을 수 없습니다. 만약 DerivedClass에서 SealedClass를 상속하려고 시도하면 컴파일 오류가 발생합니다.

Sealed 클래스를 사용하는 이유 중 일반적인 것은 다음과 같습니다:

  1. 보안 및 안정성 강화: sealed 클래스는 특정 구현을 변경하지 않고 상속을 막아 더 안정적이고 예측 가능한 코드를 만들 수 있습니다.
  2. 코드 최적화: sealed 클래스는 일부 최적화를 가능하게 하며, JIT(Just-In-Time) 컴파일러가 더 효율적인 코드를 생성할 수 있도록 합니다.
  3. API 설계 제한: 클래스의 특정 부분을 라이브러리나 API의 일부로 제공하고 싶을 때, sealed 클래스를 사용하여 해당 부분을 변경하지 못하도록 할 수 있습니다.

sealed 클래스를 사용할 때 주의할 점은 해당 클래스의 모든 멤버(메서드, 속성 등)가 자동으로 sealed 상태가 되지 않습니다. 개별 멤버에 대해서도 sealed 키워드를 사용하여 상속을 금지시켜야 합니다.

 

sealed 키워드는 주로 Class의 디자인을 확정하고, 상속을 통한 뜬금없는 변경을 방지하고자 할 때 사용하거나 더 이상 기능 추가/변경을 하지 않을 때 사용합니다.

 

 

상속이 무엇인지만 파악하고 나머지는 천천히 하나씩 개념을 잡아가면 어렵지 않습니다.