[C#] virtual, abstract, interface

✍️ virtual

  • virtual의 가장 큰 특징은 선택적인 재정의(override)가 가능하는 것이다.

  • virtual이 붙은 메서드와 속성, 인덱서는 재정의할 수 있지만 필수는 아니며 virtual 키워드가 포함된 클래스는 그 자체로도 완벽한 기능을 제공한다.

 

class Animal
{
    public virtual void Speak()
    {
        Console.WriteLine("I'm Creature");
    }
}

class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("I'm Dog!");
    }
}

class Cat : Animal
{
}
class Program
{
    static void Main(string[] args)
    {
        Animal animal = new Animal();
        Dog dog = new Dog();
        Cat cat = new Cat();

        animal.Speak(); // I'm Creature
        dog.Speak(); // I'm Dog!
        cat.Speak(); // I'm Creature
    }
}

 

🍊 abstract

  • 클래스 내부에서 abstract를 사용하려면 클래스 정의부에 abstract 키워드를 붙여줘야 한다.

  • abstract 키워드가 붙으면 그 자체로는 불완전해서 파생 클래스에서 반드시 재정의 해야 한다.
    • 단, abstract 클래스 내부에 일반 메서드와 일반 멤버 변수를 정의할 수 있다
  • abstract 키워드는 인스턴스화할 수 없다.
abstract class Animal
{
    public string name;
    public abstract void Speak();

    public void Sleep()
    {
        Console.WriteLine("Zzzzz...");
    }
}

class Dog : Animal
{
    public Dog(string name)
    {
        this.name = name;
    }

    public override void Speak()
    {
        Console.WriteLine($"I'm {name}");
    }
}

class Cat : Animal
{
    // Error ! 
}
class Program
{
    static void Main(string[] args)
    {
        Animal creature = new Animal(); // Error !
    }
}

 

  • 추상 클래스의 사용 목적은 파생 클래스에게 공통적인 정의를 제공함과 동시에 각각의 파생 클래스에 사용될 기능을 강제적으로 재정의함에 있다.
abstract class Animal
{
    public string name;
    public abstract void Speak();

    public void Sleep()
    {
        Console.WriteLine("Zzzzz...");
    }
}

class Dog : Animal
{
    public Dog(string name)
    {
        this.name = name;
    }

    public override void Speak()
    {
        Console.WriteLine($"I'm {name}");
    }
}

class Cat : Animal
{
    // Error ! 
}

 

abstract class Animal
{
    public string name;
    public abstract void Speak();

    public void Sleep()
    {
        Console.WriteLine("Zzzzz...");
    }
}

class Dog : Animal
{
    public Dog(string name)
    {
        this.name = name;
    }

    public override void Speak()
    {
        Console.WriteLine($"hello I'm {name} !!");
    }
}
class Program
{
    static void Main(string[] args)
    {
        Dog dog = new Dog("Doggy");
        dog.Speak(); // hello I'm Doggy !!
        dog.Sleep(); // Zzzzz...
    }
}

 

✨ interface

  • interface는 가장 높은 추상성을 제공한다.
    • 필드로 메서드, 프로퍼티 인덱서만 가질 수 있으며 abstract가 아닌 필드는 정의할 수 없다.
    • 접근 제한자를 사용할 수 없으며 모든 필드는 public이 적용된다.
  • abstract와 interface의 가장 큰 차이는 interface는 다중 상속이 가능하다.

  • interface는 상속의 개념보단 기능을 확장하는 개념이다.
    • 서로 관계가 없는 클래스도 동일한 interface를 구현할 수 있다.
    • 서로 관계가 없는 클래스도 interface를 구현함으로써 관계가 형성되는데 이는 다형성으로 연결된다.
abstract class Animal
{
    public abstract void Speak();
}

interface IWalk
{
    void Walk();
}

class Dog : Animal, IWalk
{
    public override void Speak()
    {
        Console.WriteLine("I'm Dog !!");
    }

    public void Walk()
    {
        Console.WriteLine("Dog : 네 발로 엉금 엉금");
    }
}

class Human : IWalk
{
    public void Walk()
    {
        Console.WriteLine("Human : 두 발로 뚜벅 뚜벅");
    }
}
class Program
{
    static void Main(string[] args)
    {
        Dog dog = new Dog();
        dog.Speak(); // I'm Dog !!
        dog.Walk();  // Dog : 네 발로 엉금 엉금

        Human human = new Human();
        human.Walk(); // Human : 두 발로 뚜벅 뚜벅
    }
}

 

다형성 개념

class Program
{
    static void Main(string[] args)
    {
        IWalk walkHuman = new Human();
        IWalk walkDog = new Dog();
        
        Test(walkHuman);
        Test(walkDog);
    }

    static void Test(IWalk walk)
    {
        // ~~        
    }
}