본문 바로가기

.NET/C#

Class(3)

728x90
반응형

클래스 3번째 시간이네요~

와 나두 잘 모르는 클래스를 포스팅한다는게 정말 만만치가 않네요 그래서인지 자료도 허접하고 내가 뭐라뭐라 써논건지도 모르겠고요 ㅜㅜ

그래도 혹시라도 제 블로그에 오셔서 도움을 받으실지도 모르는 분들을 위해서 열심히 노력해서 쓰겠습니다~^^(몇분이나 될려나 ㅜㅜ)

이번에는 클래스 필드의 속성값(?)에 대한 내용과 상속에 대해서 알아보려고합니다. 아무래도 상속이 나오면...살짝쿵 길어질지도 모르겠는데요...여러분의 인내심이 버텨주실려나 모르겠네요 ㅎㄷㄷ

클래스 멤버에는 필드, 메소드로 나눌 수 있다고 하였습니다. 보통 필드는 private로 설정해나서 외부에서의 접근을 최대한 막을려고 하는 습성이 있지요. 그래도 자신의 클래스의 메소드가 접근하는것은 기본적으로 막지 않고 있지만 그것 마져도 막을 수 있는 방법이 있습니다.

기본적으로는 막혀 있지 않지만 이 두 속성을 지정해 주면 값 변경을 막을 수 있습니다. 바로 readonly와 const입니다.

둘다 값 벼경이 불가능 한데 왜 두개나 만들어 났냐라는분이 있을 수 있는데요. 좋은 지적이지요. 두개 만들어 놓은 이유는 당연히 있습니다.

간단한 클래스의 예를 보시고 설명해드리지요

    1 class Dummy

    2 {

    3     private int dataa = 10;

    4     private readonly int datab = 10;

    5     private const int datac = 10;

    6 

    7     public Dummy()

    8     {

    9         dataa = 20;

   10         datab = 20;

   11         //datac = 20;//오류 (값할당불가)

   12     }

   13 

   14     public void TestMethod()

   15     {

   16         dataa = 30;

   17         //datab = 30;//오류 (값할당불가)

   18         //datac = 30;//오류 (값할당불가)

   19     }

   20 }

다음과 같이 있을 때 생성자에서는 readonly는 값 변경이 가능한걸 볼수가 있죠. 일반메소드에서는 값 할당이 불가능하고요
일반메소드에서는 더 강력해지죠 둘다 값 할당이 불가능한걸 볼수 있습니다. 실제로 그런지 알고 싶으시다면 주석을 풀어보시면 바로 에러라고 빨간줄이 쳐지는걸 확인 할 수 있을겁니다. ^ㅡ^

다시한번 정리 해 드리면 이렇습니다~
1. 일반 메소드 영역 : readonly, const 모두 값 할당 불가능
2. 생성자 메소드 영역 : readonly는 값 할당 가능, const는 값 할당 불가능
3. 필드 initializer영역 : readonly, const 모두 값 할당 가능

이제...상속에 대해서 써볼까 하는데요...아 어렵다 어려워 ㅜㅜ 공부하면서 포스팅하는게 정말 쉬운일이 아니군요
상속은 클래스의 재사용을 말하는 것입니다. 한번 만든 클래스를 다시 사용하여야 할 것같은데 뭔가 조금 맞지는 않는것 같고 근데 이걸 다시 쓰면 좋을꺼 같고...뭐 이럴때 상속이란 넘을 사용하는 것이지요.

1. 형식 : class 클래스이름 : 상위클래스이름 {...}
2. 하위클래스는 상위클래스의 모든 멤버를 자동으로 포함합니다.
3. 상속이 발생할 경우 하위 클래스는 상위 클래스를 확장하거나(새로운 멤버 추가) 또는 상위 클래스의 메서드를 변경하는 내용을 포함해야 합니다.
4. 하위 클래스는 상위 클래스의 모든 멤버를 포함하지만 private멤버에는 접근할 수 없습니다.
5. protected는 하위클래스에 대해서는 접근을 허용하게 해줍니다. 단 외부에서는 접근을 할 수 없는 접근지정자 입니다.
6. 두개 이상의 클래스로부터 상속을 받을 수 없습니다(다중상속 불가능)
7. 하위클래스 객체가 생성될 때 상위 클래스의 생성자 메소드가 먼저 호출된 후 하위 클래스 생성자 메소드가 호출됩니다.
8. base 키워드로 상위클래스의 생성자 메서드를 선택할 수 있습니다.

이론만 하면 정말 따분하고 지겹지요...안그래도 긴 글인데 ㅜㅜ
그럼 간단히 테스트를 해보도록 하겠습니다~. 프로젝트 생성 해주시고요. 클래스 파일을 하나 만드신후 다음과 같이 입력하겠습니다.

    1 class TheBase

    2 {

    3     private string dataa;

    4     public string Dataa

    5     {

    6         get { return dataa; }

    7         set { dataa = value; }

    8     }

    9 

   10     public TheBase()

   11     {

   12         Console.WriteLine("TheBase.Default Constructor");

   13     }

   14     public TheBase(string dataa)

   15     {

   16         this.dataa = dataa;

   17         Console.WriteLine("TheBase.Custom Constructor");

   18     }

   19 }

   20 

   21 class TheDerived : TheBase

   22 {

   23     private string datab;

   24 

   25     public TheDerived()

   26         : base()

   27     {

   28         Console.WriteLine("TheDerived.Default Constructor");

   29     }

   30     public TheDerived(string dataa, string datab)

   31         : base(dataa)

   32     {

   33         this.datab = datab;

   34         Console.WriteLine("TheDerived.Custom Constructor");

   35     }

   36 }

보시는것과 같이 TheDerived 클래스가 TheBase 클래스를 상속 받고 있습니다. 그럼 메인에서 객체 생성시 어떻게 되는지 확인해 보겠습니다.

    1 using System;

    2 using System.Collections.Generic;

    3 using System.Linq;

    4 using System.Text;

    5 

    6 namespace OOP3

    7 {

    8     class Program

    9     {

   10         static void Main(string[] args)

   11         {

   12             TheDerived deriveda = new TheDerived();

   13             deriveda = new TheDerived("상위클래스", "하위클래스");

   14         }

   15     }

   16 }

결과는 다음과 같습니다.

잘 보시면 base가 먼저 출력되고 그 뒤에 derived가 출력 되는 걸 볼 수 있습니다. 위에서 설명한 것과 같이 하위클래스 객체를 생성할때는 상위클래스가 먼저 호출되고 그 다음 하위 클래스가 호출 된다는 것을 볼 수 있지요.


그 다음 알아 볼 것은 상속관계에 있는 클래스간의 형변환을 알아보겠습니다.
상속관계에 있는 클래스간의 형변환이 가능한데요. 이것 역시 약간의 법칙(?)이 있습니다.
1. 상위클래스타입 참조 = 하위클래스타입 객체(암시적 변환)
2. 하위클래스타입 참조 = (하위클래스타입)상위클래스타입 객체 (명시적 변환)
두 클래스간의 형변환은 위의 내용에 따라서 이루어져야 합니다. 만약 그렇지 않다면...GG
한번 테스트를 해볼까요? 위에서 생성하신 프로젝트에서 클래스를 하나더 생성하시고요 다음과 같이 입력합니다.

    1 class Item

    2 {

    3     private int number;

    4     public int Number

    5     {

    6         get { return number; }

    7         set { number = value; }

    8     }

    9     private string name;

   10     public string Name

   11     {

   12         get { return name; }

   13         set { name = value; }

   14     }

   15 }

   16 class NewItem : Item

   17 {

   18     private string description;

   19     public string Description

   20     {

   21         get { return description; }

   22         set { description = value; }

   23     }

   24 }

그다음 메인에는 다음과 같이 입력하시고 실행을 해보세요

    1 class Program

    2 {

    3     static void Main(string[] args)

    4     {

    5         Item item = new NewItem();

    6         NewItem item2 = (NewItem)new Item();

    7         NewItem item3 = (NewItem)item;

    8     }

    9 }

어떠십니까?? 머찌지 않나요. 엄청난 오류가 뜨죠. 형식 캐스팅을 할 수 없다는....
그 이유는 바로 메인 6번째 줄에서 나오게 된 것입니다. 위에서 말씀드렸듯이 하위클래스타입 참조일때는 암시적 변환은 할 수 없습니다. 형변환은 참 조심해야되는데요. 런타임에서나 오류가 발생하기 때문입니다. 클래스의 형변환 참 좋은 것이지만 잘 못 쓴다면 프로그램에 참 치명적이겠지요. 이점 유의하시기 바랍니다.
6번째 줄을 주석처리하고 다시 실행을 해보면 아무것도 뜨지는 않지만 실행이 완료 될 것입니다~

다음은 참조의 타입과 객체의 타입이 다를 경우 메소드 호출 기준에 대해서 말씀드리겠습니다.(참 많죠? ㅜㅜ)
참조타입기준으로 호출하는 것은 virtual(상위타입메소드) - new(하위타입메소드) 이고 객체타입기준으로 호출 하는 것은 virtual(상위타입메소드) - override(하위타입메소드)입니다. (제가 쓴것이지만 이해 안가는 ㅜㅜ)
그냥 설명하려니 힘든데요 테스트를 통해 알아 보겠습니다.
위에서 만든 클래스를 다음과 같이 수정해보겠습니다.

    1 class Item

    2 {

    3     private int number;

    4     public int Number

    5     {

    6         get { return number; }

    7         set { number = value; }

    8     }

    9     private string name;

   10     public string Name

   11     {

   12         get { return name; }

   13         set { name = value; }

   14     }

   15     public virtual string GetInfo()

   16     {

   17         return string.Format("{0}, [{1}]", number, name);

   18     }

   19 }

   20 class NewItem : Item

   21 {

   22     private string description;

   23     public string Description

   24     {

   25         get { return description; }

   26         set { description = value; }

   27     }

   28     //public new string GetInfo() //참조타입기준메소드 호출

   29     public override string GetInfo() //객체타입기준 메소드 호출

   30     {

   31         return string.Format("{0} [{1}]", base.GetInfo(), description);

   32     }

   33 }
하위클래스의 메소드에는 new, override 지정자 두개를 만들어 두었는데요. 어떤 차이가 있는지 확인 해보시라는 의미에서 해놓았습니다. 꼭 확인을 해보시길 바랍니다 ^^
메인은 다음과 같이 수정하시고 실행해 보시면 두개의 차이점을 인지하 실수 있지 않을까 생각됩니다.

    1 class Program

    2     {

    3         static void Main(string[] args)

    4         {

    5             Item[] items = new Item[10];

    6             for (int i = 0; i < items.Length; i++)

    7             {

    8                 if (i % 2 == 0)

    9                     items[i] = new Item();

   10                 else

   11                 {

   12                     NewItem temp = new NewItem();

   13                     temp.Description = string.Format("{0}번째 아이템 설명", i + 1);

   14                     items[i] = temp;

   15                 }

   16                 items[i].Name = string.Format("{0}번째 아이템", i + 1);

   17                 items[i].Number = i + 1;

   18             }

   19             for (int i = 0; i < items.Length; i++)

   20                 TestMethod(items[i]);

   21         }

   22 

   23         private static void TestMethod(Item item)

   24         {

   25             Console.WriteLine(item.GetInfo());

   26         }

   27     }

override로 해놓으면 다음과 같은 결과가 나옵니다.

override를 new로 해보고 실행해 보시기 바랍니다. 그러면 현저히 다른 결과를 보실 수 있습니다.
또 위 코드에서 보는것과 같이 클래스도 배열로 사용이 가능합니다. 참 멋찌죠? ㅎㅎㅎㅎㅎ
단지 클래스는 참조형 배열이라는 것에 유념해여야 할 것입니다. 그렇기 때문에 다음과 같은 객체를 생성한것이지요
Item[] item = new Item();
Item[i] = new item();
클래스 배열을 만들시에는 객체 배열이 아니라 참조의 배열이라는것을 꼭 유념 하셔야 합니다 ^ㅡ^

진짜 마지막으로 한가지를 더 설명하고 마치도록 하지요
클래스를 만들때 상속이 가능하기 때문에 쉽게 클래스에 접근을 할 수 있다는 문제점이 있습니다. 또 뭔가 독특한 문법체계를 가지고 있어 다른 사람에 보여주고 싶지 않을 경우도 있을 것이고요 이럴 때는
sealed class classname 과 같은 형식으로 써주시면 상속이 불가능하게 됩니다. 나만이 쓰고 싶은 코드나 알고 있는 코드를 배포할때는 sealed를 붙여서 배포 하셔도 될것입니다.
또 partial를 통해서 같은 클래스를 만들수 있습니다. 일명 분활클래스라고 하는데요. 요넘은 컴파일될때 하나로 합쳐져 컴파일 되는 특징을 가지고 있죠

참 긴 글이 되었는데요..앞으로도 몇번의 클래스 포스트를 올릴 생각입니다. 클래스는 봐도 봐도 너무나 많은 양의 내용을 가지기 때문에 ㅜㅜ

앞으로도 많은 관심 가져주시면 감사하겠습니다.

감사합니다~~

728x90
반응형

'.NET > C#' 카테고리의 다른 글

Class(5)  (0) 2009.12.18
형변환에 대해서...  (0) 2009.12.18
System.Object 클래스 상속  (3) 2009.12.18
Property의 get, set 에 대한 간단한 정리  (0) 2009.12.18
Class(4)  (0) 2009.12.17
Class(2)  (0) 2009.12.16
Class(1)  (0) 2009.12.16
C# enum, struct  (0) 2009.12.16
C# Array 에 대해서...  (2) 2009.12.16
C# 메소드  (0) 2009.12.15