본문 바로가기
[ Program ]/c#스터디

42. 상속

by 관이119 2021. 10. 9.

상속은 쉽게 생각하면 진짜 말그대로의 의미이다.

부모클래스를 그대로 받아온다.

간단히 몇가지 형태를 알아보자.

 

그림0

 

 

그림0에 몇가지 기본형태에 대한 예제를 올려놨다.

일단 parent_class0 과 chile_class0 은 완전히 서로 다른 클래스이다. 

다만 상속을 받아서 편의상 부모클래스와 자식 클래스라고 불렀으니 해당 단어에 너무 집착하지는 말고 예제를 보자.

 

기본적으로 생각하면 child_class0 은 parent_class0 을 상속 받았으니 자식클래스인 child_class0 에서는 부모클래스인 parent_class0 의 모든메서드(함수)를 사용가능하다.

위 내용을 기본으로 load 에서 객체로 만든 한줄씩 살펴보자. (load 는 프로그램이 시작되자마자 실행됨을뜻한다. 디자이너에 있는 Form 을 더블클릭해보자)

 

첫번째줄

parent_class0 class0_0 = new parent_class0();  // 부모클래스로 객체생성

위 구문은 parent_class0 이라는 클래스의 객체를 생성한것이다.

이경우는 완전히 독립된 개체이기때문에 다른클래스의 영향을 전혀 받지않는다.

상속을 받은것도 아니고 이 클래스와 관계있는것은 아무것도 없다.

그리고 당연히 해당 클래스를 객체로 생성 했으니 해당클래스의 매서드 를 사용가능하다.

class0_0.getText0(); 을 출력하면 test0 이라는 문자가 출력될것이다.

 

두번째줄

parent_class0 class0_1 = new child_class0();   // 부모클래스 형식을 가지는 자식 클래스 객체생성

위구문은 parent_class0 타입을 가지는 child_class0 클래스 객체를 생성한것이다.

위와같이 생성하면 어떤 메서드를 호출할수 있을지 잠시 생각해보자.

결론적으로 보면 getText0 밖에 호출할수 없다.

부모클래스의 parent_class0 를 상속받은 child_class0 의 객체이지만 다시 부모클래스로 형변환 해버린것과 같다.

즉, 첫번째줄과 동일한 상태가 되버린다.

결국 이런경우 부모클래스의 함수만 호출가능하다.

 

세번째줄

child_class0 class0_2 = new child_class0();   // 자식클래스로 객체 생성

위구문은 child_class0 클래스의 객체를 생성했다.

그런데 child_class0 은 parent_class0 을 상속한 클래스이다.

그래서 parent_class0 의 모든걸 가지고 거기에 자신의 모든것 까지 가지게 된다.

결론적으로 parentclass 의 getText0 와 childclass 의 gettext_no0 함수 모두를 호출할수 있다.

 

네번째줄과 다섯번째줄

//child_class0 class0_3 = new parent_class0();

같은경우는 명시적형변환이 있다고 에러가 난다.

child_class0 class0_3 = (new parent_class0()) as child_class0;   // 부모클래스의 형식을 가지는 객체를 생성하여 자식객체로 변환

같은경우는 실제로 null 값이 나온다.

객체를 받아올수 없다는 의미이다.

정확한 이유는 알수 없지만 내부적으로 순환참조가 일어나 정상적으로 변형할수 없는것으로 생각된다. ( 자식은 부모를 상속했는데 그 부모를 다시 자식형태로 변환하고 그런데 자식은 부모를 상속했는데... 반복)

 

위와같이 상속을 사용하다보면 자식클래스에서 다른형태가 필요할때가 있다.

예를 들면 부모클래스에서는 getData() 라는 호출하면 D드라이브의 특정경로에서 파일을 읽어오게 만들놨는데 해당클래스를 상속받아서 다른사람이 만드는중에 D 드라이브가 없어 데이터 읽어오는 위치를 다른드라이브로 변경해야 하는경우가 발생할수 있다.

다음예제를 보자.

그림1

 

위 그림1처럼 자식클래스에서 경로가 변경되야 하는경우 상속에 상관없이 함수를 따로 만들어서 사용할수도 있다.

getData_e() 처럼 함수를 새로 만들수도 있다.

사실 선택의 문제이기 때문에 어떤형태로 해도 문제는 없다.

그런데 최초 parent_class 를 만든 사람은 사용자마다 다른함수를 만들라고 저런 함수를 만들어놓은건 아닐것이다.

상속해서 사용하면 누구든 별다른 구현없이 데이터를 간단하게 가져오는게 원래의 취지였을텐데 상속해서 사용하는 사람마다 따로 구현해서 사용한다면 상속해서 사용할 의미가 있을까?

그래서 최초 부모클래스를 만드는 사람은 상당히 많은 생각을 하고 모든걸 포함할수 있게 만들어야 할것이다.

그런데 현실적으로 그게 가능한일인가 생각해보면 그것도 말이 안되는이야기다.

결국 잘만들고 잘사용하고 잘정리해놔야 한다는 말이다.

 

그림2

 

위와 같이 상속받은 클래스에서 동일한 함수명을 써놓으면 new 키워드를 사용하라고 뜬다.

실제로 해보면 new 키워드를 안써도 내부적으로 new 키워드를 사용한것처럼 작동한다.

 

그림3

 

실제로 사용해줄려면 그림3처럼 사용해주면 된다.

같은 명칭의 함수형태에 new 만 추가해주면 된다.

 

그런데 실제로 parent_class 를 만드는사람도 위처럼 상속받은 사용자가 내용의 일부를 수정해서 사용하고 싶을거라고 미리 예측할수도 있다.

그래서 virtual 이라는 키워드가 존재한다.

최초 생성시 virtual 을 붙여주면 상속받은 클래스에서 override 를 사용해서 해당 메서드를 수정해서 사용할수있다.

그림4

 

그림4에서 보면 parent class 에서 getdata_aa() 라는 메서드를 virtual 로 정의 하고 상속받은 child class 에서 public override 까지만 입력하고 스페이스만 누르면 위그림처럼 사용가능한 virtual 메서드를 선택할수 있게 된다.

해당 메서드를 override 하면 기본적으로 base 를 리턴하는 구문이 생성된다. 

base 는 부모클래스를 가리키는데 결국 부모클래스 함수를 그대로 호출한다는 내용이 되겠다.

 

그림5

 

또한 virtual 메서드는 그림5처럼 base 를 없애고 완전히 새로운 내용을 정의해서 사용하거나  new 로 재정의해서 사용할수도 있다.

아래 두개 경로의 내용도 한번 읽어보자.

 

https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/virtual

 

virtual - C# 참조

virtual(C# 참조) 이 문서의 내용 --> virtual 키워드는 메서드, 속성, 인덱서 또는 이벤트 선언을 수정하고 파생 클래스에서 재정의하도록 허용하는 데 사용됩니다. 예를 들어 이 메서드는 이를 상속

docs.microsoft.com

 

https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/classes-and-structs/knowing-when-to-use-override-and-new-keywords

 

Override 및 New 키워드를 사용해야 하는 경우 - C# 프로그래밍 가이드

C#에서 new 및 override 키워드를 사용하여 기본 및 파생 클래스에서 이름이 동일한 메서드가 상호 작용하는 방식을 지정합니다.

docs.microsoft.com

 

그런데 위와같이 유연하게 사용할수 있게 해놓으면 사용자마다 통일이안되는경우가 다반사 일것이다.

그래서 형식을 강제화 할수 있게(모든사람이 동일한 형태로 만들게) 하는 키워드가 있는데 아래 두가지가 해당내용이다.

 

https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/abstract

 

abstract - C# 참조

abstract(C# 참조) 이 문서의 내용 --> abstract 한정자는 수정되는 항목에 누락되거나 불완전한 구현이 있음을 나타냅니다. abstract 한정자는 클래스, 메서드, 속성, 인덱서 및 이벤트와 함께 사용될 수

docs.microsoft.com

https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/keywords/interface

 

interface - C# 참조

:::no-loc text=interface:::(C# 참조)

docs.microsoft.com

내용은 특별한게 없다.

그냥 상속해서 쓰면된다.

강제로 해당형식을 구현해야하는것들은 구현해주면 된다.

이번장에서 말한것들은 객체지향에서 가장베이스가 되는 핵심적인 내용들인데 마구 남발하지는 말자.

사실 나는 개인적으로는 좀 회의적인 입장이다.

이런부분을 남발해놓은 프로그램들은 재사용한다고 세세하게 마구 쪼개두고 정리해둔 문서하나없이 프로그램만 덜렁있는경우가 대부분인데 오히려 수정이 엄청나게 힘들어지고 확장도 더힘들다.

결국 기본의도인 재사용이 편하고 확장이 편한 프로그램과는 거리가 멀어지는 경우가 대부분이었다.

그렇게 되면 처음만든사람들도 스스로 감당하지못해 쓸모없는 코드만 계속 늘어나고 나중에는 버그가 생겨도 어디서 생겼는지도 알수 없게 되버렸었다.

 

프로그램을 할때는 항상 "수정이 편하고 누구나 알아보기 쉽게" 가 제일 기본 베이스로 깔려야 한다.

그래야 나도 시간이 지나 수정할때 빠르게 수정할수 있고 프로그램은 잘 작동하게 된다.

이번장의 내용은 그런면에서는 상당히 어려운내용이다.

정리하면 모든걸 만들때 쓰기쉽고 수정하기 쉽게 만들고 내용들은 문서로 잘 정리해두는게 좋다고 생각한다.

 

***숙제 : 이번장에서 설명한것들을 간단한 형태로 만들어서 테스트해보자.

'[ Program ] > c#스터디' 카테고리의 다른 글

44. 로또생성기만들기  (0) 2021.10.09
43. 제네릭  (0) 2021.10.09
41.arraylist / List / StringBuilder / 참조추가법  (0) 2021.10.09
40.using/garbage collection  (0) 2021.10.09
39.property(속성)  (0) 2021.10.09

댓글