1. 인터페이스와 가상 함수, 추상 함수
virtual(가상) 함수 : 하나의 기능을 하는 완전한 클래스, 파생된 클래스에서 상속하여 재정의가 가능하나 필수가 아님
abstract(추상) 함수 : 부모 클래스에서 정의만 하고 파생된 클래스에서 상속하여 반드시 재정의를 해야함
interface(인터페이스) : 추상클래스와 비슷하지만 멤버 변수를 사용할 수 없음, 서로 다른 계층이나 타입이더라도 같은 기능을 추가하고 싶을 때 사용 (예시 : 몬스터나 플레이어나 데미지를 입는건 마찬가지이므로 해당 함수를 가진 인터페이스를 사용할 수 있다.)
abstract vs interface
interface | abstract class | |
접근 지정자 | public | private, public, protect |
구현 | 구현 불가 | 구현 가능 |
속도 | 상대적으로 느림 | 상대적으로 빠름 |
인스턴스화 | 사용 불가 | 사용 불가 |
필드 | 가질수 없음 | 필드와 상수 정의 가능 |
메소드 | 추상 메소드만 가능 | 일반 메소드도 있을수 있음 |
멤버 변수 | 사용 불가 | 사용 가능 |
2. 구조체와 클래스
구조체는 상속 불가, 값 타입, Stack에 할당
클래스는 상속 가능, 참조 타입, Heap에 할당
3. 상속성과 다형성
상속 : 부모 클래스로부터 필드, 메소드 등을 그대로 물려 받아 새로운 파생 클래스를 만드는 것
다형성 : 객체가 여러 형태를 가질수 있음
(예시 : 오버로딩을 통해 같은 이름의 메소드가 매개 변수의 개수나 타입이 다른경우)
public class EX : MonoBehaviour
{
private void print(int ex)
{
Debug.Log(ex);
}
private void print(string ex)
{
Debug.Log(ex);
}
}
(예시 : 오버라이딩을 통해 부모 클래스로 부터 물려받은 메소드를 재정의하여 사용하는 것)
public class EX : MonoBehaviour
{
protected virtual void print()
{
Debug.Log("EX Class : !");
}
protected abstract void printint ();
}
public class EX2 : EX
{
protected override void print()
{
base.print();
Debug.Log("EX2 Class : @");
}
protected override void printint()
{
Debug.Log("EX2 Class : 0");
}
}
Output :
EX Class : !
EX Class : !
EX2 Class : @
EX2 Class : 0
4. 배열과 리스트
배열은 동적 할당 불가능, List는 동적 할당이 가능
배열은 데이터의 크기가 정해져 있음, 값을 중간에 넣고 뺄 때 크기를 늘리거나 줄이는 작업이 필요해서 많은 연산 필요
리스트는 데이터의 크기가 정해져 있지 않음, 값을 중간에 넣고 뺄 때 자유로움
5. namespace와 partial
클래스이름의 중복 방지 namespace
클래스의 크기가 커서 길어지는 경우 partial로 파일을 분할하여 동일한 클래스로 작성 가능
6. 객체 지향
SOLID (솔리드) 원칙
SRP(Single Responsibility Principle, 단일책임원칙) : 클래스는 하나의 목적만 가져야 하며, 클래스를 변경하는 이유도 하나여야 한다.
OCP(Open-Closed Principle, 개방폐쇠원칙) : 클래스는 확장에는 열려 있고, 변경에는 닫혀 있어야 한다.
LSP(Liskov Substitution Principle, 리스코프치환원칙) : 상위 타입의 객체를 하위 타입으로 바꾸어도 프로그램은 일관되게 동작해야 한다.
ISP(Interface Segregation Principle, 인터페이스분리원칙) : 클라이언트는 이용하지 않는 메소드에 의존하지 않도록 인터페이스를 분리해야 한다.
DIP(Dependency Inversion Principle, 의존역전법칙) : 클라이언트는 추상화(인터페이스)에 의존해야 하며, 구체화(구현된 클래스)에 의존해서는 안된다.
7. 전역변수 vs 지역변수
전역 변수 : Heap 메모리에 저장되며 함수 외부에서 선언, 프로그램이 종료되기 전까지 파괴되지 않음
지역 변수 : Stack 메모리에 저장되며 함수 내부에서 선언, 해당 함수가 종료되면 파괴
8. delegate와 event
delegate : public으로 선언하면 클래스 외부에서 호출 가능, callback의 용도로 사용
event : public으로 선언해도 클래스 외부에서 호출 불가, 객체의 상태 변화나 사건의 발생을 알리는 용도로 사용
9. Boxing(박싱), UnBoxing(언박싱)
Boxing : 값 타입의 객체를 참조 타입으로 변환하는 작업 → Stack에 있던 값 타입의 객체를 Heap으로 이동할 때 복사가 일어난다. → Heap 영역에 복사된 영역을 참조 타입이 가르키게 된다(주소값 할당)
UnBoxing : 객체 타입의 객체를 값 타입으로 변환하는 작업 → Heap 영역에 있던 데이터를 Stack 영역으로 복사
10. object 타입에 value 타입을 대입하면
value 타입을 참조 타입으로 박싱한다. Stack영역에 있던 value를 Heap으로 복사 후 주소값을 할당
11. 세대별 GC(Garbage Collection)
0세대 : GC를 한번도 겪지 않은 갓 생성된 객체
1세대 : GC를 1회 겪은 객체
2세대 : GC를 2회 겪은 객체
세대가 낮은 메모리부터 해제를 해준 다음 메모리 컴펙션
2세대 GC를 할 시 Full Garbage Collection이라 하고 전체 Heap에 대하여 GC하는 것을 의미
세대를 나누는 근거는?
최근에 생성된 객체일수록 생명주기가 짧을 가능섶이 높고 오래된 객체일수록 생명주기가 길 가능성이 높음
최근에 생성된 객체끼리는 서로 연관성이 높을 수 있으며 비슷한 시점에 자주 액세스 됨
일부분 Heap에 대해 GC하는 것이 전체 GC를 하는것 보다 빠름
12. LOH, SOH
LOH : Large Object Heap 으로 CLR(Common Language Runtime)에서 용량이 큰(83kb이상) 객체에 사용되는 Heap
SOH : 그 이하에 평소에 사용되는 Heap
LOH는 GC시 2세대로 간주, 메모리 해제 후 메모리 컴펙션을 진행하지 않으므로 메모리 내부 단편화가 발생할 수 있음
13. Call by Value vs Call by Reference
Call By Value : 인자로 받은 값을 복사하여 처리, 넘어온 값을 증가시키거나 감소시켜도 원래의 값 보존, 값을 복사하여 사용하기 때문에 메모리 사용량이 상대적으로 늘어나 느림
Call By Reference : 인자로 받은 값의 주소를 참조하여 처리, 넘온 값을 참조하여 직접 값에 영향을 미침, 값을 참조하여 사용하기 때문에 메모리 사용량이 상대적으로 적어 빠름
14. 프로세스, 쓰레드
프로세스 : 메모리에 올라와 실행되고 있는 프로그램의 인스턴스
운영체제로부터 독립된 메모리 영역을 할당받음, 서로 독립적이라 통신이 어려움 1개 이상의 쓰레드를 가지고 있음
쓰레드 : 프로세스 내에서 할당받은 자원을 이용해 동작하는 실행 단위
쓰레드는 프로세스 내에서 Stack영역만 할당 받고 Code, Data, Heap 영역은 서로 공유, 프로세스의 자원을 공유하기 때문에 다른 쓰레드에 의한 결과를 즉시 확인 가능(통신이 쉬움)
멀티 프로세스 : 하나의 프로그램을 여러 개의 프로세스로 구성하여 1개의 작업을 처리하도록 하는 것
하나의 프로세스가 죽어도 다른 프로세스에 영향이 없음
멀티 쓰레드 : 하나의 프로그램을 여러 개의 쓰레드로 구성하여 1개의 작업을 처리하도록 하는 것
자원을 공유하기 때문에 효율적으로 사용 가능, 하나의 쓰레드의 문제가 생기면 전체 프로세스가 영향을 받음, 하나의 자원에 여러 쓰레드가 동시에 접근하면 동기화 문제가 발생할 수 있음
15. 데드락(교착상태)
한정된 자원을 여러 프로세스가 사용하고자 할 때 발생하는 상황으로 프로세스가 자원을 얻기위해 영구적으로 기다리는 상태
A라는 자원을 가진 프로세스1(P1)이 B라는 자원을 가진 프로세스2(P2)의 B가 필요하고 P2는 A가 필요할 때 데드락 발생,
뮤텍스나 세마포어 등으로 문제를 예방
16. 싱글톤 패턴 사용 이유
싱글톤 패턴 : 단 하나의 인스턴스만 생성하여 사용하는 디자인 패턴
사용하는 이유 : 단 하나의 인스턴스만 생성하는 것을 보증하고 싶은 경우 (GameManager), 메모리 낭비 방지, 인스턴스가 메모리에 올라와 있으면 언제든지 사용할수 있기 때문
'C# > Unity' 카테고리의 다른 글
[Unity C#] 형변환 속도에 대해서 (int.Parse, ToString()) (2) | 2023.11.25 |
---|---|
[Unity C#] 기술 면접 대비 중급 질문들 (1) | 2023.11.14 |
[Unity C#] foreach GC에 대하여 (0) | 2023.11.13 |
[Unity C#] FillAmount 끝자리 위치 알기 (0) | 2023.09.18 |
[Unity C#] 유니티에서 Http 통신 (0) | 2023.09.09 |