[C#] 11. 객체 지향 프로그래밍 - 다형성

치치·2024년 11월 28일
0

C#

목록 보기
13/16
post-thumbnail

📌 다형성이란?

  • 여러 개의 서로 다른 객체가 동일한 기능을 서로 다른 방법으로 처리할 수 있는 작업
  • 함수의 오버로딩
  • 함수의 오버라이딩
  • 가상함수
  • 다형성은 컴파일 시점에 함수와 속성이 결정되는 정적 바인딩을 하지 않고, 실행 시간에 함수와 속성이 결정될 수 있는 동적 바인딩을 함

    🔒바인딩 : 형식이나 멤버, 연산을 구체적으로 결정하는 과정

ex) 일반적으로 우리가 하는 정적 바인딩 (일반적인 값 데이터 호출)

class Animal
{
    public void Speak() // virtual 없이 선언
    {
        Console.WriteLine("Animal speaks!");
    }
}

class Dog : Animal
{
    public new void Speak() // new를 붙이면 부모 클래스 함수와는 다른 새로운 함수 
    {
        Console.WriteLine("Dog barks!");
    }
}
  • 메인함수에서 Animal 타입의 myAnimal 객체 선언
  • myAnimal객체를 통해 Animal 클래스의 함수 호출
class Program
{
    static void Main(string[] args)
    {
        Animal myAnimal = new Dog();
        myAnimal.Speak(); 
    }
}
  • 선언된 클래스 타입의 함수만을 호출함 ❗❗❗

📌 함수의 오버로딩

  • 같은 이름의 함수를 매개 변수의 자료형과 매개 변수의 수로 구분하여 여러 개를 선언할 수 있는 기능

동일한 이름의 Position함수
매개변수가 다 다름

class Coordinate
{
    public void Position(int x, int y)
    {
        Console.WriteLine("x : " + x);
        Console.WriteLine("y : " + y);
    }

    public void Position(float x, float y)
    {
        Console.WriteLine("x : " + x);
        Console.WriteLine("y : " + y);
    }

    public void Position(float x, float y, float z)
    {
        Console.WriteLine("x : " + x);
        Console.WriteLine("y : " + y);
        Console.WriteLine("z : " + z);
    }
}
  • 메인함수에서 참조변수 생성 후 각각의 함수를 호출해보면 다 다른 값이 출력
Coordinate coordinate = new Coordinate();

coordinate.Position(10, 10);
coordinate.Position(5.75f, 8.725f);
coordinate.Position(1.325f, 2.785f, 3.125f);

결과값 :

  • 🔒🔒 함수의 오버로딩의 경우 함수의 매개 변수에 전달하는 인수의 형태를 보고 호출하므로, 반환형으로 함수의 오버로딩은 생성할 수 없다

📌 함수의 오버라이딩

  • 상위 클래스에 있는 함수를 하위 클래스에서 재정의하여 사용하는 기능

  • 상속 관계에서만 이루어지며, 하위 클래스에서 함수 재정의를 할 때 상위 클래스의 함수형태와 일치해야 함

  • Vehicle 부모 클래스
    *Behavior 함수 정의

class Vehicle
{
    protected float velocity;

    public void Behavior()
    {
        Console.WriteLine("Vehicle Behavior");
    }
}
  • Vehicle을 상속받은 Bicycle 자식 클래스
  • new 키워드 붙이고 함수 재정의
class Bicycle : Vehicle
{
    public new void Behavior()
    {
        Console.WriteLine("Bicycle Behavior");
    }
}
  • 메인함수에서 각각의 참조변수를 만들고 함수를 호출해보면 ?
Vehicle vehicle = new Vehicle();

vehicle.Behavior();

Bicycle bicycle = new Bicycle();

bicycle.Behavior();

결과값 :

  • 함수의 형태가 부모 클래스와 자식 클래스 모두 동일함

📌 가상 함수 Virtual

  • 상속하는 클래스 내에서 같은 형태의 함수로 재정의 될 수 있는 함수

    ex) Item 부모클래스와 자식클래스인 Potion, Knife, Grenade 클래스
  • 부모 클래스에서 재정의를 원하는 함수에 virtual 키워드
  • 자식 클래스에서 재정의를 할 함수에 override 키워드
class Item
{
    public virtual void Use()
    {
        Console.WriteLine("Use Item");
    }
}

class Potion : Item
{
    public override void Use()
    {
        Console.WriteLine("Use potion");
    }
}

class Knife : Item
{
    public override void Use()
    {
        Console.WriteLine("Use Knife");
    }
}

class Grenade : Item
{
    public override void Use()
    {
        Console.WriteLine("Use Grenade");
    }
}
  • 메인 함수
  • 부모클래스의 참조변수만 정의
  • 참조변수가 포션타입의 객체를 가리켜서 함수로 접근 가능
static void Main(string[] args)
{
	Item item = null;

	Potion potion = new Potion();
	item = potion;
	item.Use();

	Knife knife = new Knife();
	item = knife;
	item.Use();

	Grenade grenade = new Grenade();
	item = grenade;
	item.Use();
}

결과값 :

  • 가상 함수의 경우 가상 함수 테이블을 사용하여 실행 시간에 호출되는 함수를 결정하며, 정적으로 선언된 함수는 가상 함수로 선언할 수 없다.
  • 가상 함수는 한 개 이상의 가상 함수를 포함하는 클래스가 있을 때 객체 주소에 가상 함수 테이블을 추가.

📌 가상 함수 테이블 이란?

  • 가상함수를 알기 위해서는 가상 함수 테이블에 대해 알아야한다 ❗
  • 가상 함수 테이블 (virtual method table == Vtable)

  • 가상 함수를 사용할 경우, 재정의한 가상 함수들의 주소값들이 테이블에 저장된다

  • Use( )함수는 가상함수로 정의

class Item
{
    public virtual void Use()
    {
        Console.WriteLine("Use Item");
    }
}

class Potion : Item
{
    public override void Use()
    {
        Console.WriteLine("Use potion");
    }
}
  • 메인 함수
  • Potion( )객체를 Item 타입의 item 참조변수 할당
static void Main(string[] args)
{
	Item item = null;

	Potion potion = new Potion();
	item = potion;
	item.Use();
}

결과값 : Use Potion이 출력 -> Potion쪽의 함수가 호출이 된 것

❓ 왜 Item 클래스의 함수가 호출되지 않고 자식 클래스가 호출된 것 일까?

  • -> 가상함수로 정의되어 있기 때문 ❗
  • -> 아래의 코드는 위의 코드를 간략하게 한 것
Item item = new Potion();
item.Use();
  • 참조 변수를 통해 객체에서 가상함수를 호출

  • 가상 함수 테이블안에는 재정의 한 함수들의 주소가 저장

  • item.Use( ); 로 함수가 호출이 되면 vtable 안에서 실제 객체의 주소를 찾고 함수 호출

📌 가상함수가 동적바인딩인 이유이다!

  • 런타임에 가상 함수 테이블을 참조해서 실제 타입을 확인하고 그 객체의 함수를 호출하는 과정이기 때문이다

  • 런타임 : 프로그램이 실제로 실행되는 시점

  • 컴파일 타임 : 프로그램이 컴파일러에 의해 번역되는 시점

ex)

class Program
{
    static void Main()
    {
        A obj = new B();
        obj.SayHello();
    }
}

컴파일 타임 : A 타입의 obj가 SayHello 메서드를 호출할 수 있음이 확인

런타임 : obj가 실제로 B 객체를 가리키고 있기 때문에 B.SayHello가 호출


네이밍 컨벤션

카멜 파스칼 스네이크

  1. 카멜
    첫 단어는 소문자, 그 이후 단어들은 첫 글자는 대문자
    myName

  2. 파스칼
    각 단어의 첫글자가 모두 대문자
    MyName

  3. 스네이크
    모든 단어는 소문자이고 _언더바를 사용
    my_name


(2024.11.27.수요일)

profile
뉴비 개발자

0개의 댓글