CTS 크기 부호 C C++ C# VB
System.Byte 1 없음 Unsigned char Unsigned char byte Byte
System.SByte 1 있음 char signed char sbyte 없음
System.Int16 2 있음 short short short Short
System.UInt16 2 있음 unsigned short unsigned short ushort 없음
System.Int32 4 있음 int int 또는 long int Integer
System.UInt32 4 없음 unsigned int unsigned(long) uint 없음
System.Int64 8 있음 long __int64 long Long
System.UInt64 8 없음 unsigned long unsigned __int64 ulong 없음
System.Char 2 없음 wchar_t wchar_t char Char
System.Single 4 있음 float float float Single
System.Double 8 있음 double double double Double
System.Decimal 16 있음 없음 Decimal decimal Decimal
System.Boolean 1   bool bool bool Boolean
System.String 가변   없음 string string String
System.Object 가변   없음 Object * object Boolean

 

C#에서 Win32 API 사용하기

 

개요

Win32 API를 불러올 때, 함수의 명칭, 인자, 리턴 값을 가지고 불러오게 되어 있다. 하지만, C#에서 타입들이 모두 객체(Object)의 형식이며, 일반적인 C 의 데이터 형과 상이한 모양을 가진다. 이러한 문제들을 해결할 수 있는 것이 PInvoke 기능이다.

 

PInvoke( Platform Invocation Service)는 관리화 코드에서 비관리화 코드를 호출할 방법을 제공한다. 일반적인 용도는 Win32 API의 호출을 위해 사용한다.

 

namespace PinvokeExample

{

using System;

 

             using System.Runtime.InteropServices; // 반드시 입력해야 한다.

 

             public class Win32

             {

                           [DllImport(“user32.dll”)]

                           public static extern int FindWindow(string a, string b);

                          

             }

}

 

위 예제는 FindWindow라는 user32.dll C함수를 사용하는 모습을 보여주고 있다. 실제 FindWindow의 선언은 다음과 같다.

 

             HWND FindWindow(LPCSTR swClassName, LPCSTR swTitle);

 

HWND는 윈도우 핸들을 표현하는 32비트 정수 이므로, int형으로 치환되고 LPCSTR 형은 NULL로 끝나는 문자열을 표현한다. 이때 PInvoke string을 자동으로 LPCSTR로 치환해 주는 역할을 하게 된다.

이 문서에서는 이처럼 Win32 API 함수의 여러 유형들을 어떻게 C#에서 사용 할 것인지에 대하여 알아보자.

 

WIN32 데이터형의 치환

Win32 API에서 일반적으로 사용하고 있는 데이터형은 모두 C#의 데이터 형으로 치환될 수 있다.

 

Win32 API TYPE

C#

BOOL, BOOLEAN

bool

BYTE

byte

CALLBACK

delegate

COLORREF

int

DWORD

int

DWORD_PTR

long

DWORD32

uint

DWORD64

ulong

FLOAT

float

HACCEL

int

HANDLE

int

HBITMAP

int

HBRUSH

int

HCONV

int

(모든 HANDLE 타입) Hxxxx

int

LPARAM

long

LPCSTR

[in] string [out] StringBuilder

LPBOOL

ref bool

이외 LP*

ref 형식

UINT

uint

Uxxxx

unsigned 타입들..

WORD

Short

WPARAM

Uint

 

 

Structure 의 전달

예를 들어 POINT 형의 경우,

typedef struct t_Point {

             int x;

             int y;

} POINT;

 

이것은 기본적으로 다음과 같이 선언될 수 있다.

[순차적]

[StructLayout(LayoutKind.Sequential)]
public struct Point {
      public int x;
      public int y;
}

 

[명시적]

[StructLayout(LayoutKind.Explicit)]
public struct Point {
      [FieldOffset(0)] public int x;
      [FieldOffset(4)] public int y;
}

 

일차적으로 할당되는 메모리 레이아웃이 동일하다면, C#에서 바로 받아 들이 수 있다.

 

// BOOL SetWindowPos(POINT pos); 이런 함수가 있다고 가정하면… ^^

 

[DllImport (“user32.dll”)]

public static extern bool SetWindowPos(Point pos);

 

사용할 함수 이름 바꾸기

여기서 함수의 이름을 바꿔서 사용하고 싶다면 다음과 같이 변경하면 된다.

 

// BOOL SetWindowPos(POINT pos);

 

[DllImport (“user32.dll”, EntryPoint = “SetWindowPos”)]

public static extern bool ShowAt(Point pos);

레퍼런스형 전달하기

 

LPPOINT형은 POINT의 포인터 형이므로 ref Point와 같이 사용 할 수 있다. 실제 사용하는 형식은 다음과 같다.

C 언어의 포인터의 경우 레퍼런스로 사용하려고 하면, ref 키워드를 사용하는 방법이 있다.

// BOOL SetWindowPos(HWND hWnd, LPRECT lpRect);

[DllImport(“user32.dll”)]

public static extern bool SetWindowPos(int hWnd, ref Rect lpRect);

 

Out형 함수 인자 사용하기

MSDN 같은 곳에서 함수의 선언을 살펴보면 다음과 같은 형식의 함수를 볼 수 있을 것이다. 이러한 형식은 레퍼런스 형으로 결과를 함수의 인자에 보내겠다는 말이다. 이러한 형식은 Win32 API에서 많이 쓰이고 있고, 포인터를 사용하므로, 많은 주의를 기울여야 한다.

 

BOOL GetWindowRect(
  HWND hWnd,      // handle to window
  LPRECT lpRect   // window coordinates
);

Parameters

hWnd

[in] Handle to the window.

lpRect

[out] Pointer to a RECT structure that receives the screen coordinates of the upper-left and lower-right corners of the window.

 

여기서 LPRECT는 앞 절에서 설명한 Structure의 전달을 참고하여 치환 될 수 있다.

여기서 lpRect RECT의 포인터이며, GetWindowRect 함수 내에서 이 포인터에 직접 값을 쓰게 되어 있다. 즉 이 포인터는 값을 기록하기 위한 인자이지, 값을 전달하기 위한 인자는 아닌 것이다. 이것은 또 다른 C# 레퍼런스 연산자인 out 키워드를 사용하여 쉽게 해결 할 수 있다.

public static extern bool GetwindowRect(int hWnd, out Rect lpRect);

 

실제 사용하는 모습은 다음과 같다.

public static extern bool GetWindowRect(int hWnd, out Rect lpRect);

public static void UseFunction() {

        Rect _rect; // 값을 대입하지 않아도 된다.

        Win32.GetWindowRect(hwnd, out _rect);

}

 

참고로 ref 키워드는 입력과 출력 둘 다 사용 할 수 있다. 그러나 ref를 사용하는 변수가 값이 설정되어 있다는 가정을 하고 있으므로, 이전에 반드시 어떠한 값을 입력해야 한다.

실제 사용 예는 다음과 같다.

public static extern bool GetWindowRect(int hWnd, ref Rect lpRect);

public static void UseFunction() {

        Rect _rect = new Rect(); // 꼭 값을 대입해야 한다.

       

        _rect.top = 20; _rect.left = 30;

        _rect.bottom = 50; _rect.right = 60;

 

        Win32.GetWindowRect(hwnd, ref _rect);

}

 

여기서 잠깐

대중없이 Rect라는 구조체가 나오는데 이는 API에서 RECT형을 C#으로 바꾸어 사용하는 structure이다. 앞의 예제들은 다음과 같은 선언을 하였다고 가정한다.

[StructLayout(LayoutKind.Explicit)]
public struct Point {
      [FieldOffset(0)] public int top;
[FieldOffset(4)] public int left;
[FieldOffset(8)] public int bottom;
[FieldOffset(12)] public int right;

}

 

 

CALLBACK 함수의 선언

C 언어에서 콜백 함수는 함수 포인터로 존재하게 된다. 이것은 함수 인스턴스의 포인터로, 함수 자체를 전달하게 되는 방식이다. 대표적으로 사용되는 부분은 EnumWindows 함수이다.

// BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARMAM IParam)

이 함수는 현재 열려 있는 모든 윈도우 핸들을 열거하기 위한 함수로 실제 처리하는 부분은 함수 포인터, 즉 콜백함수인 lpEnumFunc에서 처리하게 되어 있다. WNDENUMPROC 타입의 선언은 다음과 같다.

// typedef BOOL (CALLBACK* WNDENUMPROC)(HWND, LPARAM);

public delegate bool Callback(int hWnd, long lParam);

이러한 콜백 함수 역할을 하는 C#의 프리미티브는 delegate이다. CALLBACK delegate로 지환된다.

 

결과적으로 다음과 같이 사용하게 된다.

namespace ada.appshare

{

             public delegate bool Callback(int hwnd, int lParam);

            

             internal class Win32

             {

               

                           internal static extern int EnumWindows(CallBack x, int y);

                           [DllImport("user32.dll")]

 

                public static bool EnumWindowsCallback(int hWnd, int lParam)
                {

                        System.Console.WriteLine(“” + hWnd);

                        return true;

                }

                

             }

 

        public static void Main(String []args)

        {

                Win32.Callback call
= new Win32.Callback(Win32.EnumWindowsCallback);

                Win32.EnumWindows(call, 0);

        }

}

 

 


Posted by JJOREG
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

윈폼이라는 것에 대해서 알아봐야 할것이다.

 

MFC를 해본 나로서는 윈폼과 그에 대한 이벤트는 그렇게 까지 난해하게 다가오지는 않았다.

 

실제 MFC의 이벤트등도 VS스튜디오의 툴 내에서 손쉽게 지정이 가능하다.

 

VS C#에서도 이에대해서 충실하게 지원해준다.

 

 

 

보면 왼쪽에 있는 툴박스에서 버튼 컨트롤을 선택한후 오른쪽에 보이는 속성창에서 이벤트등을 생성해 줄수 있다.

 

MFC와 거의 동일한 인터페이스 이다.

 

이벤트란 간단히 말해서

버튼을 눌렀다.

창을 키웠다.

창을 움직였다 등을 의미합니다.

 

그러한 이벤트가 벌어졌을시 특정한 행동을 해라. 라는것이 기본적인 이벤트의 사용법 입니다.

 

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

그러한 이벤트가 벌어졌을시 특정한 행동을 해라. 라는것이 기본적인 이벤트의 사용법 입니다.

Posted by JJOREG

시간을 알려주는 구조체이다. 사용법은 아래와 같고.

자세한 내용은 msdn의 구조체 항목에서 datetime 구조체를 참고하면 된다.


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;


namespace ConsoleApplication1

{

    class Program

    {


        static void Main(string[] args)

        {

            DateTime dt = DateTime.Now;


            string str;


            str = string.Format("금일은 {0}년 {1}월 {2}일({3})이다", dt.Year, dt.Month, dt.Day, dt.DayOfWeek);

            Console.WriteLine(str);

            str = string.Format("현재 {0}시 {1}분 {2}초({3})이다", dt.Hour, dt.Minute, dt.Second, dt.Millisecond);

            Console.WriteLine(str);

            str = string.Format("dt.Date {0}", dt.Date);

            Console.WriteLine(str);

            str = string.Format("짧은 날짜 형식 {0}", dt.ToShortDateString());

            Console.WriteLine(str);

        }

    }

}

Posted by JJOREG

namespace ConsoleApplication1

{

    struct MyData

    {

        public int x, y;


        public MyData(int x, int y)

        {

            this.x = x;

            this.y = y;

        }


        public MyData(ref int x, ref int y)

        {

            this.x = 0;

            this.y = 0;

        }


        public void NoShow()

        {

            Console.WriteLine("no swap");

            Console.WriteLine("{0}        {1}", this.x, this.y);

        }


        public void Show()

        {

            Console.WriteLine("swap");

            Console.WriteLine("{0}        {1}", this.x, this.y);

        }

    }


    class MyDataClass

    {

        public int x = 10, y = 100;


        public void NoShow()

        {

            Console.WriteLine("No swap");

            Console.WriteLine("{0}        {1}", x, y);

        }


        public void Show()

        {

            Console.WriteLine("swap");

            Console.WriteLine("{0}        {1}", x, y);

        }

    }


    class Swap

    {


        static public void CSwapdata(MyDataClass md)

        {

            int temp;

            temp = md.x;

            md.x = md.y;

            md.y = temp;

        }


        static public void CSwapdata1(ref MyDataClass md)

        {

            int temp;

            temp = md.x;

            md.x = md.y;

            md.y = temp;

        }


        static public void Swapdata(MyData md)

        {

            int temp;

            temp = md.x;

            md.x = md.y;

            md.y = temp;

        }


        static public void Swapdata1(ref MyData md)

        {

            int temp;

            temp = md.x;

            md.x = md.y;

            md.y = temp;

        }

    }


    class Program

    {


        static void Main(string[] args)

        {

            MyData Md = new MyData(10, 100);


            MyData Md1;

            Md1.x = 10;

            Md1.y = 100;


            Console.WriteLine("new struct value");


            Md.NoShow();


            Swap.Swapdata(Md);


            Md.Show();


            Console.WriteLine("new struct ref");


            Md.NoShow();


            Swap.Swapdata1(ref Md);


            Md.Show();


            Console.WriteLine("value struct value");


            Md1.NoShow();


            Swap.Swapdata(Md1);


            Md1.Show();


            Console.WriteLine("value struct ref");


            Md1.NoShow();


            Swap.Swapdata1(ref Md1);


            Md1.Show();


            MyDataClass CMd = new MyDataClass();


            Console.WriteLine("class value swap");


            CMd.NoShow();


            Swap.CSwapdata(CMd);


            CMd.Show();


            Console.WriteLine("class ref swap");


            CMd.NoShow();


            Swap.CSwapdata1(ref CMd);


            CMd.Show();


        }

    }

}


구문이 좀 길지만 실행해보면 차이를 알수 있다.


구조체의 경우 ref로 참조하지 않을 경우 원본의 데이터를 바꿀수 없다.

이것은 구조체를 new로 할당하거나 그냥 할당해도 마찬가지이다.


클래스의 경우에는 반대이다. 어떤 방식으로 넣어도(ref로 넣던 값형으로 넣던) 내부의 데이터를 변경할수가 있다.


즉 클래스는 애초부터 참조형 형태의 데이터이고 구조체의 경우에는 값형 데이터이며 이 차이를 명확하게 인식해야 한다.

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

C# 프로그래밍 <윈폼> <이벤트> <델리게이트>  (0) 2014.01.10
DateTime 구조체  (0) 2013.12.30
변수가 사용됐다? 초기화의 순서는?  (0) 2013.12.30
인덱서  (0) 2013.12.30
구조체  (0) 2013.12.30
Posted by JJOREG

빠르게 배워나가는 도중이기 때문에 변수나 함수에 대해서 깊게 파고 있지는 않았다.

하지만 C#에서는 몇가지 새로운 경고와 변수의 사용시점등이 약간 다른 면이 있어서 다음과 같이 정리해 보았다.


    class aaa

    {

        private int c = 0; -> 선언 순간 초기화. 봐도 신기하기는 하다.


        public void a()

        {

            this.c = 1;

        }

    }


위의 클래스를 컴파일 하면 다음과 같은 경고가 뜬다.

경고 CS0414: 'ConsoleApplication1.aaa.c' 필드가 할당되었지만 그 값은 사용되지 않습니다.

사용되지 않았다? 그냥 상수 값의 대입은 컴파일러가 사용하지 않았다라고 판단하는 것 같다.

그럼 어떤때 사용했다고 할까?



    class aaa

    {

        private int c = 100;


        public void a()

        {

            int dd = 100;

            this.c = dd; -> 이 녀석을 대입하면 사용했다고 본다. 상수가 지역변수등을 혹은 public void a(int temp) { this.c = temp;} 같은 식도 된다.

            b(this.c); -> 아무것도 없는 함수지만 내부에 넣었다는 것만으로도 사용한 것으로 본다.

        }


        public void b(int a)

        {

        }


        public void p()

        {

            Console.WriteLine(c); -> 마찬가지다.

        }


        public aaa(int a)

        {

            this.c = a; -> 생성자를 만들어서 대입해주면 역시나 사용했다고 인식한다.

        }


    }

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

DateTime 구조체  (0) 2013.12.30
클래스와 구조체, 참조형과, 값형  (0) 2013.12.30
인덱서  (0) 2013.12.30
구조체  (0) 2013.12.30
추상 클래스와 인터페이스의 차이란?  (0) 2013.12.29
Posted by JJOREG

인덱서란? ------------------------------------------------------------------------------------------------------------------------


  인덱서란 내부에 존재하는 맴버변수나 혹은 인스턴스를 배열과 같이 취급하는 것을 인덱서라고 한다.

  문법적으로는 C#의 속성의 배열 버전이라고 보면 된다 보인다.


    class SampleCollection<T>

    {

        private T[] arr = new T[100]; -> 어라 클래스의 맴버변수를 내부에서 그냥 초기화 해버린다. 가능했구나...

  private int c = 0; -> 이렇게 굳이 할당을 하지 않아도 가능하다.

        public T this[int i] -> 이녀석이 인덱서이다. this구문을 무조건 붙여줘야 한다.

        {

            get

            {

                return arr[i]; -> 내부 인스턴스의 값을 배열적인 측면으로 접근이 가능하다.

            }

            set

            {

                arr[i] = value; -> 마찬가지로 대입도 가능하다.

            }

        }

    }


    // This class shows how client code uses the indexer

    class Program

    {

        static void Main(string[] args)

        {

            SampleCollection<string> stringCollection = new SampleCollection<string>();

            stringCollection[0] = "Hello, World"; -> 객체에서 즉각 접근이 가능해진다.

            stringCollection[1] = "World, Hello"; -> 배열이니 인덱스를 바꾸는 것도 마찬가지.

            System.Console.WriteLine(stringCollection[1]);

        }

    }

Posted by JJOREG

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

일단 구조체의 사용법을 좀 보자.


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;


namespace ConsoleApplication1

{

    interface a

    {

    }


    struct Player : a

    {

        public string name;

        public int Att;

        public int Def;

        public int Hp;

        public int Dex;


        public Player(string name, int Att, int Def, int Hp, int Dex) -> 생성자를 만들었다면

        {

            this.name   = name;

            this.Att    = Att;

            this.Def    = Def;

            this.Hp     = Hp;

            this.Dex    = Dex; -> 내부에서 마지막 맴버까지 모든 맴버를 초기화 시켜줘야 한다. 그렇지 않으면 오류가 난다.

        }

        public void Show()

        {

            Console.WriteLine(name + "의 능력:");

            Console.WriteLine("공격력: " + Att + ", 방어력: " + Def + ", 체력:" + Hp + ", 민첩성: " + Dex);

        }

    }


    class Program

    {

        static void Main(string[] args)

        {

            Player Player1 = new Player("수깔", 94, 96, 84, 92);

            Player1.Show();


            Player Player2;

            Player2.name = "빨딴";

            Player2.Att = 100;

            Player2.Def = 84;

            Player2.Hp = 96;

            Player2.Dex = 86;

            Player2.Show();

        }

    }

}


c++에서 사용하는 구조체와 동일하게 이용이 가능하나 다음과 같은 차이가 생겼다.

1. 인터페이스를 제외하고는 상속이 불가능하다.(c++에서는 구조체도 클래스 상속이 가능했습니다. 아니 구조체와 클래스의 차이가 없다고 봐도 무방할 정도다.)

2. 디폴트 생성자를 지원하지 않는다.(생성자를 만들어 놓지 않으면 경고가 미친듯이 뜬다. 컴파일은 된다.)

3. 또한 initilizer를 지원하지 않는다. 무슨 말이냐면.


    struct Player

    {

        public int Att = 0; -> 구조체는 이런식으로 초기화가 불가능하다.

    }

4. 구조체는 명시적매개변수가 없는 명시적 생성자를 포함할수 없다.


    struct MyData

    {

        private int x, y;

        public MyData() -> 이런 녀석은 만들 수가 없다.

        {

            this.x = 0;

            this.y = 0;

        }

    }


5. 또한 내부의 static변수는 내부의 모든 맴버가 초기화 하기 전까지는 사용이 불가능하다.


    namespace ConsoleApplication1

    {

        interface a

        {

        }


        struct Player : a

        {

            public string name;

            public int Att;

            public int Def;

            public int Hp;

            static public int Dex;


            public Player(string name, int Att, int Def, int Hp, int Dex)

            {

                this.name = name;

                this.Att = Att;

                this.Def = Def;

                this.Hp = Hp;

            }

            public void Show()

            {

                Console.WriteLine(name + "의 능력:");

                Console.WriteLine("공격력: " + Att + ", 방어력: " + Def + ", 체력:" + Hp + ", 민첩성: " + Dex);

            }


            public void SetDex()

            {

                Dex = 100; -> 보면 알겠지만 static 맴버는 this라는 

            }

        }


        class Program

        {

            static void Main(string[] args)

            {

                Player Player1;

                //Player1.SetDex();

                Player1 = new Player("수깔", 94, 96, 84, 92);

                Player1.Show();

                Player1.SetDex(); -> 모든 변수가 초기화된 후에야 사용이 가능하다.


                Player Player2;

                Player2.name = "빨딴";

                Player2.Att = 100;

                Player2.Def = 84;

                Player2.Hp = 96; -> //Player2.Hp = 96; 초기화중 모든 맴버를 할당하지 않고 사용하려고 하면 오류가 뜬다. 할당되지 않은 지역변수를 사용했다는 오류다.

                                   // 그래서 내부적으로 맴버를 사용하지 않는 함수를 만들어서 시험해 사용해봤으나 마찬가지의 결과가 나왔다.

 // 즉 귀찮게 생각하지 말고 무조건 static맴버를 제외하고는 초기화 시켜라!

                Player2.Show();

                Player1.Show();

            }

        }

    }


7. 마지막으로 구조체는 값형의 데이터이다. 따로 주소가 할당되지 않기 때문에. 그냥 값형을 인자로 받는 함수에 넣을 경우 원본 데이터에는 아무런 영향이 가지 않는다.



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

변수가 사용됐다? 초기화의 순서는?  (0) 2013.12.30
인덱서  (0) 2013.12.30
추상 클래스와 인터페이스의 차이란?  (0) 2013.12.29
추상 클래스 봉인 클래스  (0) 2013.12.29
인터페이스  (0) 2013.12.29
Posted by JJOREG

[C#] 인터페이스, 추상클래스, 클래스

Programming/.NET Programming 2009/05/31 05:11

인터페이스, 추상클래스, 클래스 용어 정리

인터페이스 : 가장 기본적으로 가질 수 있는 공통 기능을 포함하고 있는 것
                이것을 일반 클래스에 여러개의 상속해서 사용
---> 팀프로젝트에서 주로 사용, 필요한 함수들을 미리 선언하고, 여러 부분으로 나눠서 각각 따로 구현하니까 자신이 구현하는 부분이 아닌 나머지 부분은 구현되있다고 (상속을 받는다거나) 가정하고 코딩

추상클래스 : 비슷하거나 같은 기능을 포함, 이름은 같고, 하는 일은 비슷하거나 같지만 구현 내용(방식)이 다를 때 사용

클래스
 : 가장 일반적인 클래스를 말하며, 인터페이스나 추상클래스로부터 상속받은 뒤 추가적인 기능을 구현하여 각각의 새로운 객체로 만들 떄 사용
---> class안에 class를 선언할 수 있지만, methode안에는 class를 선언할 수 없다.


인터페이스, 추상클래스, 클래스의 특징

인터페이스 : method의 원형만 선언할 수 있음
1. 변수 선언 불가능
2. 함수 정의 불가능
3. 함수 원형 선언 가능

추상클래스 : 추상 method를 가질 수 있는 클래스, 객체 가질 수 없음 (class 생성 불가)
1. 변수 선언 가능
2. 함수 정의 가능
3. 함수 원형만 선언 가능

클래스 : 가장 일반적인 Class
1. 변수 선언 가능
2. 함수 정의 가능
3. 함수 원형만 선언은 불가능, 정의도 해줘야 함

상속 관계
1. 인터페이스 → 인터페이스 (가능)
2. 인터페이스 → 추상클래스 (가능)
3. 인터페이스 → 일반클래스 (가능)
4. 추상클래스 → 일반클래스 (가능) : 추상함수 정의를 해야함
5. 추상클래스 → 추상클래스 (가능)
6. 일반클래스 → 추상클래스 (가능)
7. 일반클래스 → 일반클래스 (가능)
8. 추상클래스 → 인터페이스 (불가능)
9. 일반클래스 → 인터페이스 (불가능)
 


인터페이스, 추상클래스, 클래스 예제

using System;


namespace Study

{

    /// <summary>

    /// 인터페이스

    /// </summary>

    interface 인터페이스

    {

        // int a; // 변수 선언 X

        // void test(){}; // 함수 정의 X

        void Test1(); // 함수 선언만 가능

    }

 

    /// <summary>

    /// 추상클래스

    /// </summary>

    abstract class 추상클래스

    {

        int a; // 변수 선언 O

        void Test1() // 함수 정의, 선언 O

        {

            a++;

        }

        public abstract void Test2(); // 추상함수(선언만 하는 함수)

    }

 

    /// <summary>

    /// 일반클래스

    /// </summary>

    class 추상클래스 : 일반클래스 // 추상클래스로부터 상속받음

    {

        public static void Main(string[] args)

        {

        }

        public override void Test2() // 추상함수를 override해 줌

        {

            throw new NotImplementedException();

        }

    }

}




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

인덱서  (0) 2013.12.30
구조체  (0) 2013.12.30
추상 클래스 봉인 클래스  (0) 2013.12.29
인터페이스  (0) 2013.12.29
C#에서 const  (0) 2013.12.29
Posted by JJOREG

abstract 키워드를 사용하면 불완전하여 파생 클래스에서 구현해야 하는 클래스 및 클래스 멤버를 만들 수 있습니다.

sealed 키워드를 사용하면 이전에 virtual로 표시되었던 클래스나 특정 클래스 멤버가 상속되지 못하도록 할 수 있습니다.

클래스 정의 앞에 abstract 키워드를 배치하여 클래스를 추상으로 선언할 수 있습니다. 예를 들어, 다음과 같습니다.

public abstract class A
{
    // Class members here.
}


추상 클래스는 인스턴스화할 수 없습니다. 추상 클래스의 목적은 여러 파생 클래스에서 공유할 수 있는 기본 클래스의 공통적인 정의를 제공하는 것입니다. 예를 들어 클래스 라이브러리에서 여러 자체 함수에 매개 변수로 사용되는 추상 클래스를 정의한 다음 해당 라이브러리를 사용하는 프로그래머가 파생 클래스를 만들어 클래스의 고유 구현을 제공하도록 할 수 있습니다.

추상 클래스에서는 추상 메서드도 정의할 수 있습니다. 메서드의 반환 형식 앞에 abstract 키워드를 추가하면 추상 메서드가 정의됩니다. 예를 들면 다음과 같습니다.

public abstract class A
{
    public abstract void DoWork(int i);
}


추상 메서드에는 구현이 없으므로 메서드 정의 다음에는 일반적인 메서드 블록 대신 세미콜론이 옵니다. 추상 클래스의 파생 클래스에서는 모든 추상 메서드를 구현해야 합니다. 추상 클래스에서 기본 클래스의 가상 메서드를 상속하는 경우 추상 클래스에서는 추상 메서드를 사용하여 가상 메서드를 재정의할 수 있습니다. 예를 들면 다음과 같습니다.

// compile with: /target:library
public class D
{
    public virtual void DoWork(int i)
    {
        // Original implementation.
    }
}

public abstract class E : D
{
    public abstract override void DoWork(int i);
}

public class F : E
{
    public override void DoWork(int i)
    {
        // New implementation.
    }
}


virtual 메서드는 abstract로 선언되어도 추상 클래스에서 상속된 모든 클래스에 대해 여전히 가상입니다. 추상 메서드를 상속하는 클래스에서는 메서드의 원본 구현에 액세스할 수 없습니다. 앞의 예제에서 F 클래스의 DoWork에서는 D 클래스의 DoWork를 호출할 수 없습니다. 따라서 추상 클래스는 파생 클래스에서 가상 메서드에 대한 새 메서드 구현을 반드시 제공하도록 제한할 수 있습니다.

클래스 정의 앞에 sealed를 배치하여 클래스를 sealed로 선언할 수 있습니다. 예를 들어, 다음과 같습니다.

public sealed class D
{
    // Class members here.
}


봉인 클래스는 기본 클래스로 사용할 수 없습니다. 그러므로 추상 클래스가 될 수도 없습니다. 봉인 클래스는 상속할 수 없습니다. 봉인 클래스는 기본 클래스로 사용될 수 없으므로 일부 런타임 최적화에서는 봉인 클래스 호출이 약간 더 빨라집니다.

기본 클래스의 가상 멤버를 재정의하는 파생 클래스의 클래스 멤버, 메서드, 필드, 속성 또는 이벤트를 봉인으로 선언할 수 있습니다. 이렇게 하면 이후에 파생되는 클래스에서는 해당 멤버가 가상이 아니게 됩니다. 클래스 멤버 선언에서 override 키워드 앞에 sealed키워드를 넣으면 멤버가 봉인으로 선언됩니다. 예를 들면 다음과 같습니다.

public class D : C
{
    public sealed override void DoWork() { }
}



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

구조체  (0) 2013.12.30
추상 클래스와 인터페이스의 차이란?  (0) 2013.12.29
인터페이스  (0) 2013.12.29
C#에서 const  (0) 2013.12.29
c#에서의 다형성  (0) 2013.12.27
Posted by JJOREG

인터페이스란? ----------------------------------------------------------------------------


  c# 에서는 기본적으로 다중상속을 지원하지 않는다.


  class a {}

  cass b {}

  class c : a, b {} -> 이런식의 상속은 불가능하다는 것이다.


  하지만 인터페이스라는 녀석은 실행가능한 코드를 포함하지 않는 특수한 클래스로서. 마치 c++의 순수가상클래스와 비슷한 역할을 한다.



    class Program

    {

        static void Main(string[] args)

        {

            SubA _Sub = new SubB();


            _Sub.Fun();

        }

    }


    interface InterA -> 인터페이스의 선언부분이다.

    {

        void Fun(); -> 구현은 없는 선언을 인터페이스의 필드에 포함시킨다.

    }


    class SubA : InterA -> 인터페이스를 상속한다.

    {

        public virtual void Fun() -> 이런식으로 가상함수로 정의가 가능하다.

        {

            Console.WriteLine("zzzzz"); -> 순수가상함수를 상속한 클래스와 비슷하다. 인터페이스에 존재하는 함수의 구현을 포함시켜야 문법적으로 오류가 나지 않는다.

        }

    }


    class SubB : SubA -> 인터페이스를 구현하고 있는 클래스를 상속했다.

    {

        public override void Fun() -> 당연히 오버라이드도 가능하다.

        {

            Console.WriteLine("XXXX");

        }

    }


다중상속은 지원하지 않지만 다중 인터페이스 상속은 지원한다. 


    interface Inter1

    {

    }


    interface Inter2

    {

    }


    class SubA : Inter1, Inter2

    {

    }


클래스와 함께 상속시킬 수도 있다.


    interface Inter1

    {

    }


    interface Inter2

    {

    }


    class SubB

    {

    }


    class SubA : SubB, Inter1, Inter2 -> 인터페이스는 이렇게 몇개든 상속이 가능하다.

    {

    }

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

추상 클래스와 인터페이스의 차이란?  (0) 2013.12.29
추상 클래스 봉인 클래스  (0) 2013.12.29
C#에서 const  (0) 2013.12.29
c#에서의 다형성  (0) 2013.12.27
제네릭(generic), 함수, 변수 개념.  (0) 2013.12.27
Posted by JJOREG
이전버튼 1 2 3 이전버튼