미니드론 자율비행을 준비하면서 팀원들이 C#에 대해 따로 정리한 자료들입니다.
# 객체 지향 프로그래밍(OOP = Object Oriented Programming)
→ 코드 내의 모든 객체로 표현하고자 하는 프로그래밍 패러다임
* 객체 : 세상의 모든 것을 지칭하는 단어
→ 속성 : 크기, 종류, 파일 생성 날짜, 데이터(변수)
→ 기능 : 수정, 삭제, 메소드
* 클래스(Class) : 객체를 만들기 위한 청사진,
데이터와 메소드를 묶는 집합,
기본 데이터 형식을 조합한 복합 데이터 형식(참조 형식)
C#의 모든 형식이 클래스
ex) int a = 30; 클래스 : int(정수를 담는 객체를 위한 청사진)
int b = 40; 객체 : a, b(실제로 데이터를 담을 수 있는 실제 객체)
- 객체를 클래스의 실체(instance), 인스턴스라고 부른다.
* 클래스 선언
class 클래스이름
{
// 데이터와 메소드
}
→ 필드(Field) : 클래스 안에 선언된 변수
→ 멤버(Member) : 클래스 내에 선언되어 있는 요소
→ 생성자(Constructor) : 클래스의 이름과 동일한 이름을 가지고, 객체를 생성하는 역할
→ new 키워드 : 생성자를 호출해서 객체를 생성하는 데 사용되는 연산자
- new 연산자와 생성자는 함께 사용(모든 데이터 형식에 사용)
ex)
using System;
namespace BasicClass
{
Class Cat
{
public string Name;
public string Color;
public void Meow() 실행결과
{ 키티 : 야옹
Console.WriteLine(“{0} : 야옹”, Name); 키티 : 하얀색
} 네로 : 야옹
} 네로 : 검은색
class MainApp
{
static void Main(string[] args)
{
Cat kitty = new Cat();
kitty.Color = “하얀색”;
kitty.Name = “키티”;
kitty.Meow();
Console.WriteLine(“{0} : {1}”, kitty.Name, kitty.Color);
Cat nero = new Cat();
nero.Color = “검은색”;
nero.Name = “네로”;
nero.Meow();
Console.WriteLine(“{0} : {1}”, nero.Name, nero.Color);
}
}
}
* 생성자의 선언
→ 클래스와 이름이 같고 반환 형식이 없다.(해당 형식(클래스)의 객체를 생성하는 것뿐)
메소드와 마찬가지로 오버로딩이 가능해서 다양한 버전의 생성자를 준비해 놓을 수 있다.
class 클래스이름
{
한정자 클래스이름( 매개변수목록 ) 생성자
{
//
}
// 필드
// 메소드
}
- 클래스를 선언할 때 생성자를 구현하지 않아도 컴파일러에서 생성자를 만들어준다.
그럼에도 생성자를 구현하는 이유는 클래스의 필드 때문이다. 객체의 필드를 원하는 값으로 초기화하고 싶을 때 이 작업을 할 수 있는 최적의 장소가 객체를 생성하기 위해 호출하는 메소드인 생성자이기 때문이다.
- 매개 변수가 없는 생성자는 컴파일러가 자동으로 생성해준 생성자를 호출할 때처럼 사용하고 매개 변수가 있는 버 전의 생성자는 생성자의 괄호 안에 필요한 매개 변수를 입력한다.
- 프로그래머가 생성자를 하나라도 직접 정의하면 C# 컴파일러는 매개 변수 없는 기본 생성자를 제공하지 않는다.
* 소멸자
→ 객체를 파괴한다.
→ 클래스 이름 앞에 ~를 붙인 형태. 매개 변수가 없고 한정자도 사용하지 않는다.
여러 버전의 소멸자를 만드는 오버로딩도 불가능하고 직접 호출할 수도 없다.
CLR의 가비지 컬렉터가 객체가 소멸되는 시점을 판단해서 소멸자를 호출해준다.
class 클래스이름
{
~클래스이름() 소멸자
{
//
}
// 필드
// 메소드
}
- 소멸자를 사용하지 말 것을 권장하는 이유
1) CLR의 가비지 컬렉터가 언제 동작할지 예측할 수 없다.
2) 명시적으로 소멸자가 구현되어 있으면 가비지 컬렉터가 상속받은 Finalize() 메소드를 클래스의 족보를 타고 올 라가며 호출하기에 응용 프로그램의 성능 저하만 가져올 확률이 높다.
3) CLR의 가비지 컬렉터는 우리보다 훨씬 더 똑똑하게 객체의 소멸을 처리할 수 있다.
* 정적 필드
→ 메소드나 필드가 클래스의 인스턴스가 아닌 클래스 자체에 소속되도록 지정하는 한정자
→ 프로그램 안에서 인스턴스는 여러 개지만 클래스는 단 하나이므로 필드가 클래스에 소속된다는 것은 프로그램
전체에서 유일하게 존재한다는 것을 의미
- static으로 한정되지 않은 필드는 자동으로 인스턴스에 소속되고 static으로 한정한 필드는 클래스에 소속된다.
- 프로그램 전체에 걸쳐 공유해야 하는 변수가 있을 때 정적 필드를 이용한다.
인스턴스에 소속된 필드의 경우 클래스에 소속된 필드의 경우(static)
class MyClass class MyClass
{ {
public int a; public static int a;
public int b; public static int b;
} }
public static void Main() public static void Main()
{ {
MyClass obj1 = new MyClass(); MyClass.a = 1;
obj1.a = 1; MyClass.b = 2;
obj1.b = 2; }
MyClass obj2 = new MyClass();
obj2.a = 3;
obj2.b = 4;
}
* 정적 메소드
→ 정적 필드처럼 인스턴스가 아닌 클래스 자체에 소속된다.
클래스의 인스턴스를 생성하지 않아도 호출이 가능한 메소드이다.
→ 비정적 메소드는 인스턴스에 소속된다고 인스턴스 메소드라고 한다.
클래스의 인스턴스를 생성해야만 호출할 수 있는 메소드이다.
* 객체 복사
- 얕은 복사(Shallow Copy)
→ 객체를 복사할 때 참조만 살짝 복사하는 것
- 깊은 복사(Deep Copy)
→ target이 힙에 보관되어 있는 내용을 source로부터 복사해서 받아 별도의 힙 공간에 객체를 보관하는 것
→ c#에서는 자동으로 해주는 구문을 제공하지 않으므로 우리가 수행하는 코드를 만들어야 한다.
* this 키워드
→ 객체가 자신을 지칭할 때 사용하는 키워드
- 객체 외부에서 객체의 필드나 메소드에 접근할 때 객체의 이름을 사용하고 객체 내부에서 자신의 필드나 메소드에 접근할 때 this 키워드를 사용한다.
* this() 생성자
→ 자기 자신의 생성자를 가리킨다.
생성자에서만 사용될 수 있고 생성자의 코드 블록의 안쪽이 아닌 앞쪽에서만 사용이 가능하다.
* 은닉성(Encapsulation)
→ 클래스의 사용자에게 필요한 최소의 기능만을 노출하고 내부를 감출 것을 요구하는 것
- 필드는 상수를 제외하고 무조건 감추는 것이 좋다.
* 접근 한정자(Access Modifier)
→ 감추고 싶은 것은 감추고 보여주고 싶은 것은 보여주도록 코드를 수식하고 필드, 메소드를 비롯해 프로퍼티 등 모든 요소에 대해 사용할 수 있다.
- c# 접근 한정자의 종류
1) public : 클래스의 내부/외부 모든 곳에서 접근할 수 있다.
2) protected : 클래스의 외부에서는 접근할 수 없지만 파생 클래스에서는 접근이 가능하다.
3) private : 클래스의 내부에서만 접근할 수 있고 파생 클래스에서도 접근이 불가능하다.
4) internal : 같은 어셈블리에 있는 코드에 대해서만 public으로 접근할 수 있다.
다른 어셈블리에 있는 코드에서는 private와 같은 수준의 접근성을 가진다.
5) protected internal : 같은 어셈블리에 있는 코드에 대해서만 protected로 접근할 수 있다.
다른 어셈블리에 있는 코드는 private와 같은 수준의 접근성을 가진다.
→ 접근 한정자로 수식하지 않은 클래스의 멤버는 무조건 private로 접근 수준이 자동으로 지정된다.
* 예외(Exception)
→ 기대했던 것 외의 상황이 발생한 것(=에러(Error))
* 상속
→ 물려받는 클래스(파생 클래스(Derived Class), 자식 클래스)가 유산을 물려줄 클래스(기반 클래스(Base Class), 부모 클래스)를 지정한다.
→ 파생 클래스의 이름 뒤에 콜론(:)을 붙여주고 그 뒤에 상속받을 기반 클래스의 이름을 붙여주면 된다.
- 파생 클래스는 자신만의 고유한 멤버 외에 기반 클래스로부터 물려받은 멤버를 가진다.
→ 파생 클래스는 객체를 생성할 때 내부적으로 기반 클래스의 생성자를 호출한 우에 자신의 생성자를 호출하고 객 체가 소멸할 때는 반대의 순서로 소멸자를 호출한다.
* base 키워드
→ base는 기반 클래스를 가리키고 이를 통해 기반 클래스의 멤버에 접근할 수 있다.
- 파생 클라스의 생성자에서 기반 클래스의 생성자에게 매개 변수를 넘겨주는 방법
→ base()에 매개 변수를 넘겨 호출하면 Base() 생성자를 통해 Name 필드를 초기화 할 수 있다.
* sealed 한정자
→ 기반클래스의 작성자가 의도하지 않은 상속이나 파생 클라스의 구현을 막기 위해 상속이 불가능하도록 클래스를 선언하면 이 클래스는 상속 봉인(봉인 클래스)이 되어 상속 시도가 컴파일되면 에러를 출력한다.
* 기반 클래스와 파생 클래스 사이에서는 족보를 오르내리는 형식 변환이 가능.
→ 파생 클래스의 인스턴스는 기반 클래스의 인스턴스로도 사용할 수 있다.
→ 이를 통해 코드의 생산성이 높아진다.
* 형번환 연산자
1) is 연산자
→ 객체가 해당 형식에 해당하는지를 검사하여 그 결과를 bool 값으로 반환한다.
2) as 연산자
→ 형식 변환 연산자와 같은 역할을 한다.
→ 형변환 연산자가 변환에 실패하는 경우 예외를 던지는 반면에 as 연산자는 객체 참조를 null로 만든다.
- 형식 변환 연산자 대신 as 연산자를 사용하는 쪽이 권장된다.
→ 형식 변환에 실패해도 예외가 일어나 갑자기 코드의 실행이 점프하는 일이 없으므로 코드를 관리하기가 더 수월 하기 때문이다.(as 연산자는 참조 형식에 대해서만 사용이 가능, 값 형식의 객체는 형식 변환 연산자 사용)
* 다형성(Polymorphism) (하위 형식 다형성의 준말)
→ 객체가 여러 형태를 가질 수 있음을 의미
자신으로부터 상속받아 만들어진 파생 클래스를 통해 다형성을 실현한다는 뜻.
* 오버라이딩(Overriding)
→ 메소드를 재정의하는 것
- 메소드를 오버라이딩하기 위한 조건
→ 오버라이딩을 할 메소드가 virtual 키워드로 한정되어 있어야 한다는 것.
- private로 선언한 메소드는 오버라이딩 할 수 없다.
* 메소드 숨기기
→ CLR에게 기반 클래스에서 구현된 버전의 메소드를 감추고 파생 클래스에서 구현된 버전만을 보여주는 것
파생 클래스 버전의 메소드를 new 한정자로 수식함으로써 할 수 있다.(생성자를 호출할 때 new와 다르다)
→ 메소드 숨기기를 통해 오버라이딩과 같은 효과를 얻을 수 있으나 메소드 숨기기와 오버라이딩은 다르다.
이름처럼 메소드를 숨기고 있을 뿐이다. 객체를 선언하면 CLR에게 Base 버전의 메소드가 노출되어 실행된다.
* 오버라이딩 봉인
→ 메소드를 오버라이딩되지 않도록 봉인할 수 있으나 virtual로 선언된 가상 메소드를 오버라이딩한 버전의 메소드 만 가능하다.
→ 브레이크 역할인 sealed 한정자를 사용한다.
* 중첩 클래스(Nested Class)
→ 클래스 안에 선언되어 있는 클래스
→ 자신이 소속되어 있는 클래스의 멤버에 자유롭게 접근할 수 있고 private 멤버에도 접근할 수 있다.
- 중첩 클래스를 쓰는 이유
1) 클래스 외부에 공개하고 싶지 않은 형식을 만들고자 할 때
2) 현재의 클래스의 일부분처럼 표현할 수 있는 클래스를 만들고자 할 때
* 분할 클래스(Partial Class)
→ 여러 번에 나눠서 구현하는 클래스
클래스의 구현이 길어질 때 나눠서 구현함으로써 소스 코드 관리의 편의를 제공
몇 개로 분할 구현했는지 하나로 구현했는지 신경쓸 필요없이 하나의 클래스인 것처럼 사용
→ partial 키워드를 이용해서 작성
* 확장 메소드(Extension Method)
→ 기존 클래스의 기능을 확장하는 기법
기반 클래스를 물려받아 파생 클래스를 만든 뒤 추가하는 상속과 다르다.
- 확장 메소드를 선언하는 방법
→ 메소드를 선언하되 static 한정자로 수식해야 한다.
이 메소드의 첫 번째 매개 변수는 반드시 this 키워드와 함께 확장하고자 하는 클래스의 인스턴스여야 한다.
그 뒤에 따라오는 매개 변수 목록이 실제로 확장 메소드를 호출할 때 입력되는 매개 변수이다.
메소드는 클래스 없이 선언될 수 없으므로 클래스를 하나 선언하고 그 안에 확장 메소드를 선언한다.
이 때 선언하는 클래스도 static 한정자로 수식해야 한다.
- 확장 메소드를 사용하면 string 클래스에 문자열을 뒤집는 기능을 넣을 수도 있고 int 형식에 제곱 연산 기능을 넣을 수도 있다.
* 구조체(Structure)
→ 클래스와 비슷하지만 클래스는 참조 형식이고 구조체는 값 형식이다.
구조체의 인스턴스는 스택에 할당되고 인스턴스가 선언된 블록이 끝나는 지점에서 메모리가 사라진다.
→ struct 키워드를 이용해서 선언한다.
→ 구조체는 값 형식이기에 할당 연산자 =를 통해 모든 필드가 그대로 복사된다.
→ 구조체는 생성자를 호출할 때 외에는 new 연산자를 사용하지 않아도 인스턴스를 만들 수 있다.
특징 | 클래스 | 구조체 |
키워드 | class | struct |
형식 | 참조 형식 | 값 형식 |
복사 | 얕은 복사 | 깊은 복사 |
인스턴스 생성 | new 연산자와 생성자 필요 | 선언만으로도 생성 |
생성자 | 매개 변수 없는 생성자 선언 가능 | 매개 변수 없는 생성자 선언 불가능 |
상속 | 가능 | 모든 구조체는 System.Object 형식을 상속하는 System.ValueType으로부터 직접 상속받음 |
'교외활동 > 공모전' 카테고리의 다른 글
연산자 (0) | 2018.05.30 |
---|---|
C언어 데이터의 정의 (0) | 2018.05.27 |
2017 KEPCO 대학생 서포터즈 (한국전력공사) 피드백 (0) | 2018.05.22 |
바이로봇 패트론 (전기학회 미니드론 자율비행 경진대회) (Byrobot petrone) 후기 및 피드백 (3) (0) | 2018.05.17 |
바이로봇 패트론 (전기학회 미니드론 자율비행 경진대회) (Byrobot petrone) 후기 및 피드백 (2) (0) | 2018.05.15 |