C#에서의 다형성은 -----------------------------------------------------------------------------------------------------------------------------


C++에서의 다형성과 비교해서 확인해보자.


C++에서의 다형성 이라고 하면.


1. 클래스로서의 다형성 (부모클래스의 하위클래스들은 부모클래스의 이름으로 사용될수 있고 그에 대한 인자나 파라매터로 사용이 가능하다.)

2. 함수로서의 다형성(부모클래스와 같은 이름의 함수를 사용하거나 자식클래스는 부모 클래스의 함수를 같은 이름으로 오버라이드 할수 있다.)


/// 다형성을 사용한 일반적인 C++ 코드

class A

{

public: 

virtual void virfun(void) {cout << "im A fun!" << endl;}

};


class B

: public A

{

public: 

virtual void virfun(void) {cout << "im B fun!" << endl;}

};


class C

: public B

{

public: 

virtual void virfun(void) {cout << "im C fun!" << endl;}

};


int _tmain(int argc, _TCHAR* argv[])

{


//A aaa;

//B bbb;

//C ccc;


//ccc = bbb;

//aaa = bbb;


A* aaa = new A;

B* bbb = new B;

C* ccc = new C;

A* aaaB;

A* aaaC;


aaaB = bbb;

aaaC = ccc;


aaa->virfun();   -> A클래스의 virfun()을  호출한다.

aaaB->virfun(); -> B클래스의 virfun()을 호출한다.

aaaC->virfun(); -> C클래스의 virfun()을 호출한다.


delete aaa;

aaa = NULL;

delete bbb;

bbb = NULL;

delete ccc;

ccc = NULL;


return 0;

}


/// 비슷하게 짜본 C# 코드
namespace Extension
{
    class A
    {
        public virtual void Fuc() { Console.WriteLine("Afun"); }
    }

    class B : A
    {
        public override void Fuc() { Console.WriteLine("Bfun"); }
    }

    class C : B
    {
        public override void Fuc() { Console.WriteLine("Cfun"); }
    }


    namespace ConsoleApplication1
    {
        class Program
        {
            unsafe int* p1 = null;

            static void Main(string[] args)
            {
                A aaa = new A();
                B bbb = new B();
                C ccc = new C();

                A aaaB;
                A aaaC;
                aaaB = bbb;
                aaaC = ccc;

                aaa.Fuc(); -> A클래스의 fun()을  호출한다.
                aaaB.Fuc(); -> B클래스의 fun()을  호출한다.
                aaaC.Fuc(); -> C클래스의 fun()을  호출한다.
            }
        }
    }
}


MSDN을 확인해보자. ----------------------------------------------------------------------------------------------------------------------------


C#은 컴파일 타임에 정적으로 형식이 지정되므로 변수를 선언하고 나면 해당 형식을 변수의 형식으로 변환하지 않는 한 변수를 다시 선언하거나 다른 형식의 값을 저장하는 데 사용할 수 없습니다. 예를 들어 정수를 임의의 문자열로 변환할 수 없습니다. 따라서 다음 코드에서 볼 수 있는 것처럼 i를 정수로 선언한 후에는 해당 변수에 문자열 "Hello"를 할당할 수 없습니다.

int i;
i = "Hello"; // Error: "Cannot implicitly convert type 'string' to 'int'"

하지만 값을 다른 형식의 변수나 메서드 매개 변수에 복사해야 하는 경우가 있습니다. 예를 들어 double 형식의 매개 변수를 사용하는 메서드에 정수 변수를 전달해야 하거나 클래스 변수를 인터페이스 형식의 변수에 할당해야 할 경우가 있습니다. 이런 종류의 작업을형식 변환이라고 합니다. C#에서는 다음과 같은 변환을 수행할 수 있습니다.

  • 암시적 변환: 변환의 형식 안전성이 유지되며 데이터가 손실되지 않으므로 특수한 구문이 필요 없습니다. 작은 정수 형식에서 큰 정수 형식으로의 변환, 파생 클래스에서 기본 클래스로의 변환 등이 여기에 포함됩니다.

  • 명시적 변환(캐스트): 명시적 변환에는 캐스트 연산자가 필요합니다. 캐스팅은 변환 시 정보가 손실될 수 있거나 다른 이유로 변환이 성공하지 못할 수 있을 때 필요합니다. 일반적인 예제에는 숫자를 정밀도가 낮거나 범위가 작은 형식으로 변환, 기본 클래스 인스턴스를 파생 클래스로 변환하는 것을 포함합니다.

  • 사용자 정의 변환: 사용자 정의 변환은 기본 클래스-파생 클래스 관계가 없는 사용자 지정 형식 간의 명시적 변환과 암시적 변환이 가능하도록 사용자가 정의할 수 있는 특수한 메서드를 통해 수행됩니다. 자세한 내용은 변환 연산자(C# 프로그래밍 가이드)를 참조하십시오.

  • 도우미 클래스를 사용한 변환: 정수와 System.DateTime 개체 또는 16진수 문자열과 바이트 배열과 같이 서로 호환되지 않는 형식 간에 변환하려면 Int32.Parse와 같은 기본 제공 숫자 형식의 System.BitConverter 클래스, System.Convert 클래스 및 Parse 메서드를 사용합니다. 자세한 내용은 방법: 바이트 배열을 정수로 변환(C# 프로그래밍 가이드)방법: 문자열을 숫자로 변환(C# 프로그래밍 가이드) 및 방법: 16진수 문자열과 숫자 형식 간 변환(C# 프로그래밍 가이드)을 참조하십시오.

기본 제공 숫자 형식의 경우 저장되는 값을 자르거나 반올림하지 않고 변수에 저장할 수 있으면 암시적 변환을 수행할 수 있습니다. 예를 들어, long(8바이트 정수) 형식의 변수에는 int(32비트 컴퓨터에서 4바이트)에 저장할 수 있는 모든 값을 저장할 수 있습니다. 다음 예제의 경우 컴파일러에서는 우변에 있는 값을 bigNum에 할당하기 전에 암시적으로 long 형식으로 변환합니다.

// Implicit conversion. num long can
// hold any value an int can hold, and more!
int num = 2147483647;
long bigNum = num;


암시적 숫자 변환의 전체 목록은 암시적 숫자 변환 표(C# 참조)를 참조하십시오.

참조 형식의 경우 특정 클래스에서 해당 클래스의 직접 또는 간접 기본 클래스나 인터페이스로의 암시적 변환이 항상 존재합니다. 이 경우 파생 클래스는 항상 기본 클래스의 모든 멤버를 포함하기 때문에 특별한 구문이 필요 없습니다.

Derived d = new Derived();
Base b = d; // Always OK.

하지만 정보가 손실될 위험이 없이 변환을 수행할 수 없는 경우에는 컴파일러에서 캐스트라는 명시적 변환을 수행하도록 합니다. 캐스트는 컴파일러에게 변환을 수행하는 의도와 데이터 손실이 발생할 수 있다는 것을 인식하고 있다는 명시적으로 알리는 방법입니다.캐스팅을 수행하려면 변환할 값이나 변수 앞에 캐스팅하려는 형식을 괄호로 둘러쌉니다. 다음 프로그램에서는 double을 int로 캐스팅합니다. 캐스팅하지 않으면 프로그램이 컴파일되지 않습니다.

class Test
{
    static void Main()
    {
        double x = 1234.7;
        int a;
        // Cast double to int.
        a = (int)x;
        System.Console.WriteLine(a);
    }
}
// Output: 1234


허용되는 명시적 숫자 변환의 목록은 명시적 숫자 변환 표(C# 참조)를 참조하십시오.

참조 형식의 경우 기본 형식을 파생 형식으로 변환해야 한다면 명시적 캐스트가 필요합니다.

// Create a new derived type.
Giraffe g = new Giraffe();

// Implicit conversion to base type is safe.
Animal a = g;

// Explicit conversion is required to cast back
// to derived type. Note: This will compile but will
// throw an exception at run time if the right-side
// object is not in fact a Giraffe.
Giraffe g2 = (Giraffe) a;

참조 형식 사이에 캐스트 연산을 수행하면 내부 개체의 런타임 형식은 변경되지 않고 해당 개체에 대한 참조로 사용되는 값의 형식만 변경됩니다. 자세한 내용은 다형성(C# 프로그래밍 가이드)를 참조하십시오.

일부 참조 형식 변환에서는 컴파일러가 캐스트의 유효성 여부를 확인하지 못합니다. 따라서 올바르게 컴파일된 캐스트 작업이 런타임에 실패할 수 있습니다. 다음 예제에서 볼 수 있는 것처럼, 런타임에 실패하는 형식 캐스트는 InvalidCastException을 throw하게 됩니다.

class Animal
{
    public void Eat() { Console.WriteLine("Eating."); }
    public override string ToString()
    {
        return "I am an animal.";
    }
}
class Reptile : Animal { }
class Mammal : Animal { }

class UnSafeCast
{
    static void Main()
    {            
        Test(new Mammal());

        // Keep the console window open in debug mode.
        System.Console.WriteLine("Press any key to exit.");
        System.Console.ReadKey();
    }

    static void Test(Animal a)
    {
        // Cause InvalidCastException at run time 
        // because Mammal is not convertible to Reptile.
        Reptile r = (Reptile)a;
    }

}


'게임개발공부 > C#공부' 카테고리의 다른 글

인터페이스  (0) 2013.12.29
C#에서 const  (0) 2013.12.29
제네릭(generic), 함수, 변수 개념.  (0) 2013.12.27
속성(property)  (0) 2013.12.27
override 문법의 직관화  (0) 2013.12.20
Posted by JJOREG