교외활동/공모전

객체 지향 프로그래밍 (C#)

cchucchu 2018. 5. 23. 18:30
반응형

미니드론 자율비행을 준비하면서 팀원들이 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으로부터 직접 상속받음

 

반응형