강께르의 개발일지
[수업] 20210916_4일차 본문
오버로딩과 오버라이딩이 섞인 상황
변수가 참조하고 있는 인스턴스 기준으로 매개변수를 결정해 오버로딩 메소드를 호출하지 않고
변수 그 자체 기준으로 매개변수를 결정해 오버로딩 메소드를 호출한다.
->
변수가 자식 인스턴스를 참조해도 변수 데이터형이 부모 클래스이면
부모 클래스형의 오버로딩 함수를 호출한다.
오버로딩 : 컴파일 타임에 어떤 함수를 호출할지 결정된다.
오버라이딩 : 런타임에 어떤 함수를 호출할지 결정된다.
System.object 클래스
모든 데이터형을 상속해주는 클래스
어떤 데이터형이든 오브젝트 클래스로 암시적 형변환 가능하다.
기본 데이터형은 구조체인데 object 클래스 형변환이 가능하다.
그래서 기본 데이터형도 object형으로 매개변수를 받을 수 있다!
Stack 클래스 예
스택 내부의 데이터 관리를 object로 관리해서 어떤 데이터형이 들어올 수 있다.
만약 스택 데이터에서 pop을 수행한다면 그 데이터형에 다운캐스팅해서 가져올 수 있다.
boxing / unboxing
boxing : 값형 변수를 참조형 변수로 형 변환 경우, 스택 -> 힙
unboxing : 참조형 변수를 값형 변수로 형 변화 경우, 힙 -> 스택
예 )
스택 영역에 먼저 올라온 int형 변수에 3을 대입
힙 영역에 올라갈 오브젝트형 변수에 int형 변수 값을 대입 (boxing, 힙 영역에 박스 공간을 만든다는 것)
스택 영역의 int형 변수의 값을 바꿔도
힙 영역에 영향을 주지 않아.
그냥 int형 변수에 바로 대입하는 것은 컴파일 타임에 타입 검사를 하지만,
다운캐스팅하여 int형 변수로 대입하는 경우에는 런타임으로 검사하기에 타입에 대한 보장을 장담할 수 없다.
박싱했을 때의 데이터형과 언박싱했을 때의 형변환 데이터형이 다르면 프로그램이 죽기 때문이다.
이를 위해서 제네릭으로 일반화 프로그래밍을 하려고 한다.
배열의 경우 박싱 언박싱이 안된다.
참조형 변수들의 배열만이 오브젝트 배열로 박싱이 된다.
Object형으로 구현된 메소드들에 대해서 다 오버라이딩할 수 있다.
ToString(), Equals(), GetType() 등
reflection 타입 정보를 이용해서 메소드 호출하려면 그 메소드를 포함하고 있는 클래스형으로 형 변환해줘야하는데 그냥 메소드 이름으로 호출하는 것.
구조체
ValueType 클래스를 상속받은 녀석
struct 키워드로 선언 정의
멤버는 클래스와 동일하게 가진다
차이점 - 클래스 : 참조형식 동작 / 구조체 : 값형식 동작
구조체의 문법적 제약
기본생성자 X (미리 정의된 것이 있기에 덮어쓰기 X)
필드 초기화 X
비할당된 멤버가 있으면 X
소멸자 X
상속 X(인터페이스 제외)
-> 컴파일 단계에서 에러가 날 수 있다.
구조체는 default를 갖진다.
멤버는 모두 기본값을 가지는 구조체로 생성된다.
기본 생성자와 같은 일을 한다.
매개변수로 전달하는 구조체는 깊은 복사로 값을 복사한다.
만약 그 구조체가 너무 크거나 함수가 자주 호출되는 것이라면
구조체를 매개변수로 넘길 때, 살짝 고민해봐야할 문제다.
readonley형 구조체 : 모든 멤버가 readonly형 멤버이면 그런 구조체로 만들 수 있다.
메소드 내의 구조체 선언은 스택영역에, 클래스의 멤버로 구조체 선언이면 힙 영역에 올라간다.
구조체의 ref 선언
값 형식인데 힙으로 올라가는 게 에러가 난다.
클래스와 서로 다른 점
값형과 참조형
상속 차이
기본 생성자 차이
등 등
클래스와 구조체 선택 기준
제약 조건에 빗대어 생각하자.
상속할 거리가 있다 : 클래스
할당 연산에 있어 깊은 복사가 필요 : 구조체
클래스로 올라가는 애들은 가비지 컬렉터의 체크 대상이기에...
하지만 이것은 고려사항이 아니다.
어셈블리 = 하나의 프로젝트
프로젝트 하나당 실행파일 혹은 라이브러리 결과물이 나올 수 있다.
internal : public과 유사, 다른 프로젝트에선 접근 막힌다.
protected internal : 다른 프로젝트에서 상속관계에서만 접근 가능
privated protected : 다른 프로젝트에선 막아버리는 것
클래스를 접근 권한 없이 선언한다면 기본 internal로 선언된다
같은 어셈블리에서만 동작하게 된다.
msdn을 참조할 것.
부모 클래스가 선언한 접근 권한보다 범위가 작거나 같은 접근권한을 자식 클래스에서 가져야 한다.
인터페이스
예시) IEnumerator / ICompable
인터페이스는 추상 클래스와 비교되는 것
추상클래스 : 추상 함수가 옵션
인터페이스 : 추상 함수만 가질 수 있다.
구현이 안되어 있고 선언만 되어있다. 싹 다 public 접근권한이다.
클래스 / 구조체 모두 인터페이스를 상속받을 수 있다.
인터페이스에 선언된 메소드에 대해 상속받은 클래스는 무조건 재정의해줘야 한다.
항상 public 권한으로 상속에서 구현해줘야한다.
override라고 쓰지 않지만 override 방식으로 작동한다.
인터페이스는 접두사로 I를 붙여주는 게 관행이다.
인터페이스가 클래스와 다른 점
인터페이스로 다중 상속이 가능하다.
여러 인터페이스를 하나의 클래스에게 상속해줄 수 있다.
다중 상속이 메소드 이름이 일치하는 경우는?
재구현된 메소드가 하나밖에 없다고 컴파일 단계에서 에러가 난다.
해당 인터페이스의 메소드라는 의미로 (인터페이스 이름).(메소드 이름)으로 재정의해줘야 한다.
오히려 둘 다 이름을 붙여주면 에러난다. 왜?
기존 함수가 있고 또 다른 인터페이스의 함수가 있다는 의미로 써야한다.
해당 인스턴스를 참조하는 변수를 원하는 인터페이스로 형 변환해서 메소드를 호출하는 방법밖에 없다.
인터페이스에게 상속 받은 클래스에서 메소드를 가상 함수로 만들면
그 하위 클래스로 override로 해 오버라이딩할 수 있다.
자식 클래스가 인터페이스를 중복해 직접 받는다면
똑같은 인터페이스를 상속받은 부모 클래스에 멤버 하이딩이 일어날 수 있어 private로 바꾸고 인터페이스의 이름을 달아주는 방식으로 살릴 수는 있다. 근데 굳이 이렇게까지..?
인터페이스도 boxing이 일어날 수 있다.
참조형으로 동작하는 인터페이스
구조체가 인터페이스를 상속받는다면 구조체로 인터페이스형으로 형 변환을 한다면 boxing이 일어난다.
인터페이스와 추상 클래스의 선택 기준
모든 클래스가 상속받지 않는 애매한 기준에 메소드만 넘겨주는 목적으로
인터페이스화하여 클래스로 만드는 것을 지양한다.
공유되는 속성 -> 클래스
공유되는 옵션, 기능 추가 -> 인터페이스
열거형
사용자 정의 데이터형
값 형식
열거형 선언시 가질 값도 같이 정의해줘야 한다.
문법 : (접근 권한) enum { 바디 }
사용할 때 : (enum 데이터형 이름) (식별자) = (enum 데이터형 이름).(enum의 값)
int형 정수와 매핑된다.
enum의 값들이 정수 중 하나랑 매핑돼 있다.
특정 데이터형으로 지정 가능
public enum BorderSide : short { Left = 1, Right, Top = 10, Bottom }
정수랑 형 변환이 가능하다.
암시적 형 변환은 허용되지 않는다.
명시적 형 변환만 가능!
저장할 때는 정수 값으로 저장된다.
기존의 열거형을 끌어다가 새로운 열거형의 값으로 선언 정의할 수 있다.
다른 열거형으로 형 변환은 정수형을 한번 거쳤다가 그 열거형으로 형 변환을 수행한다.
열거형 변수에 0을 할당하는 경우에만 명시적 형 변환을 해주지 않아도 된다.
'프로그래밍 > C#' 카테고리의 다른 글
[수업] 20210917_5일차 (0) | 2021.09.18 |
---|---|
[문제 풀기] boxing, unboxing과 인터페이스에 대하여 (0) | 2021.09.17 |
[문제 풀기] 클래스에 관하여 (0) | 2021.09.16 |
[수업] 20210915_3일차 (0) | 2021.09.16 |
[수업] 20210914_2일차 (0) | 2021.09.14 |