[C#] class 상속(Inheritance)

[C#] class 상속(Inheritance)

상속(Inheritance)는 상속은 객체지향 프로그래밍에서 중요한 개념 중 하나로, 기본 클래스(부모 클래스)의 필드와 메드를 상속하거나 재정의 하여 새로운 파생 클래스(자식 클래스를)를 정의하는 것을 말합니다. 상속을 통해 코드의 재사용성을 높이며 설계의 효율성을 높이고, 유연성과 확장성을 제공하고 다형성을 지원합니다. 또한 유지보수성이 향상되어 시간과 비용 절약의 장점도 있습니다.

예를 들어 동물을 의미하는 CAnimal 클래스와 강아지를 의미하는 CDog 클래스를 구현한다고 했을 때, 강아지는 동물에 속하므로 CDog 클래스는 CAnimal 클래스를 상속 받으면 됩니다. 상속 받는 class에서 콜론(:)을 사용하면 상속 받을 클래스를 적어주면 됩니다.

public class CAnimal
{
    public CAnimal()
    {
    }
}

public class CDog : CAnimal
{
    public CDog()
    {
    }
}

위의 경우 CAnimal는 기본 클래스 또는 부모 클래스라고 불리며 CDog는 파생 클래스, 자식 클래스라고 합니다.
자식 클래스는 부모 클래스의 필드, 메드,속성을 상속 받습니다. 아래 코드는 CAnimal의 필드, 메드, 속성 상속 받는 예제 코드입니다.

public class CAnimal
{
    protected string strName;

    public string Name
    {
        get { return strName; }
        set { strName = value; }
    }

    public CAnimal()
    {
        strName = "동물";
    }

    public string Info()
    {
        return strName;
    }
}

public class CDog : CAnimal
{
    public CDog()
    {
        strName = "강아지";
    }
}

class Program
{
    static void Main(string[] args)
    {
		CDog dog = new CDog;
		Console.WriteLine(dog.Name);
		Console.WriteLine(dog.Info());
    }
}
접근 제한자와 상속 관계
접근 제한자설명상속 관계에서의 접근 가능 여부
public모든 클래스에서 접근 가능가능
protected부모와 자식 클래스에서만 접근 가능가능
private같은 클래스 내부에서만 접근 가능불가능
internal같은 어셈블리 내에서 접근 가능가능 (같은 어셈블리일 경우)
protected internal같은 어셈블리 또는 상속 관계의 자식 클래스에서만 접근 가능가능

상속을 한다고 모든 부모 클래스의 데이터를 사용할 수 있는 것은 아닙니다. 상속을 할 때 접근 제한자를 통해 필드, 메소드, 속성 등 접근 범위를 제어합니다.

virtual, override - 메소드 재정의(Overriding)

위에서 상속 받은 부모 클래스의 메소드를 자식 클래스에서 사용할 수 있다고 설명했었는데, 재정의 또한 가능합니다. 재정의를 통해 동작을 변경하거나 확장할 수 있습니다.

메소드 재정의를 위해 아래 규칙을 따릅니다.

  • 부모 클래스에서 메소드에 virtual 키워드 삽입하여 선언
  • 자식 클래스에서 메소드에 override 키워드 삽입하여 재정의

아래는 메소드 재정의 예제 코드입니다.

public class CAnimal
{
    protected string strName;

    public string Name
    {
        get { return strName; }
        set { strName = value; }
    }

    public CAnimal()
    {
        strName = "동물";
    }

    public virtual string Sound()
    {
        return "소리";
    }

    public virtual string Move()
    {
        return "이동";
    }

    public virtual string Eat()
    {
        return "먹기";
    }

    public string Info()
    {
        return strName;
    }
}
public class CDog : CAnimal
{

    public CDog()
    {
        strName = "강아지";
    }

    public override string Sound
    {
        return "멍멍";
    }

    public override string Move(
    {
        return "네발로 이동";
    }

    public override string Eat()
    {
        return "사료 먹기";
    }
}
abstract - 추상화

abstract 키워드를 클래스에 붙이면 추상 클래스가 되며, 추상 클래스의 메소드에만 abstract를 사용할 수 있습니다. abstract는 구현되지 않은 메소드를 정의할 때 사용됩니다.
기본 클래스에서 선언된 추상 메소드는 파생 클래스에서 반드시 구현되어야 합니다. 또한 추상 클래스는 객체로 생성할 수 없습니다.

public abstract class CAnimal
{
    public CAnimal()
    {
        strName = "동물";
    }

    public abstract string Sound();
}
public class CDog : CAnimal
{
    public CDog()
    {
        strName = "강아지";
    }
    //정의하지 않으면 에러가 발생합니다.
    //public override string Sound()
    //{
    //    return "멍멍";
    //}
}

class Program
{
    static void Main(string[] args)
    {
        CAnimal anim = new CAnimal(); // 추상 클래스는 객체로 생성할 수 없습니다.
    }
}

아래는 위 코드의 결과입니다.

new

반대로 객체의 다형성을 지원할 필요가 없을 때, 기본 클래스와 동일한 이름의 멤버를 숨기고, 새로운 멤버를 정의할 때 사용됩니다.

class CAnimal
{
    public void Speak()
    {
        Console.WriteLine("동물이 소리를 냅니다.");
    }
}

class CDog : CAnimal
{
    public new void Speak()
    {
        Console.WriteLine("멍멍!");
    }
}

class Program
{
    static void Main()
    {
        CAnimal animal = new CDog();
        animal.Speak(); // 동물이 소리를 냅니다.

        CDog dog = new CDog();
        dog.Speak(); // 멍멍!
    }
}
abstract, virtual, override, new 비교

아래 표의 목적에 맞게 사용하면 됩니다.

키워드목적부모 클래스 메소드 필요 여부재정의 여부런타임 다형성 지원
abstract추상 메서드를 정의. 파생 클래스에서 반드시 구현해야 함필요반드시 재정의해야 함지원 (재정의 강제)
virtual부모 메서드를 기본 구현으로 제공하며, 재정의가 선택 사항임필요선택적으로 재정의 가능지원
override부모 클래스의 abstract 또는 virtual 메서드를 재정의필요재정의 시 사용지원
new부모 클래스의 동일한 이름의 메서드를 숨기고, 새로운 메서드를 정의필요하지 않음재정의가 아님지원하지 않음