1) 캡슐화(encapsulation)
캡슐화란 객체의 필드, 메서드를 하나로 묶고, 실제 구현 내용을 감추는 것을 말한다. 필드와 메서드를 캡슐화하여 보호하는 이유는 외부의 잘못된 사용으로 인해 객체가 손상되지 않도록 하는 데 있다.
캡슐화가 잘 된 클래스는 사용하는 입장에서도 편리하다. 클래스의 이름 자체에서 이미 제공되는 기능을 대략 파악할 수 있고, 외부로 제공해야 할 기능에 대해서만 정확하게 public으로 노출한다.
2) 정보 은닉(information hiding)
외부에서 멤버 변수를 직접 접근할 수 없게 만드는 것이다. 접근이라는 단어에는 읽기(read)와 쓰기(write)라는 두 가지 의미가 있다. 필드에 읽고 쓰기가 적용될 때는 관례적으로 get과 set이라는 단어를 각각 사용한다. get/set기능을 하는 메서드를 특별히 접근자 메서드(getter), 설정자 메서드(setter)라고 한다.
정보 은닉의 원칙
- 특별한 이유를 제외하고는 필드를 절대 public으로 선언하지 않는다.
- 접근이 필요할 때는 접근자/설정자 메서드를 만들어 외부에서 접근하는 경로를 클래스 개발자의 관리하에 둔다.
ex)
class Car
{
int i_speed; // 정보은닉
public void Set_speed(int _i_speed)
{
if(_i_speed > 150) // 인자의 범위를 제한
{
_i_speed = 150;
}
i_speed = _i_speed;
}
public int Get_speed()
{
return i_speed;
}
}
namespace _2020_06_01_002
{
class Program
{
static void Main(string[] args)
{
Car Mycar = new Car();
Mycar.Set_speed(100);
Console.WriteLine("현재속도: 시속 {0}km", Mycar.Get_speed());
Mycar.Set_speed(300);
Console.WriteLine("현재속도: 시속 {0}km", Mycar.Get_speed());
}
}
}
cf. 모듈화
프로그램을 분석하고 추상화하여 소프트웨어의 성능을 향상시키거나 프로그램의 시험, 통합 및 수정을 용이하게 하는 설계 및 구현 기법이다.
장점
- 프로그램의 효율적인 관리 및 성능 향상
- 전체적인 소프트웨어 이해의 용이성 증대 및 복잡성 감소
- 소프트웨어 시험, 통합, 수정 시 용이성 제공
- 기능의 분리가 가능하고 인터페이스가 단순
- 오류의 파급 효과를 최소화
- 모듈의 재사용 가능으로 개발과 유지보수가 용이
단점
- 모듈 간 결합도의 최소화
- 모듈 내 요소들 간의 응집도 최대화
3) 프로퍼티(property)
호출을 위한 메서드 정의를 일일이 코드로 작성하자면 번거롭다. 따라서 프로퍼티를 이용하여 단순하게 작성할 수 있다.
class 클래스_명
{
접근제한자 타입 프로퍼티_명
{
접근제한자 get
{
//코드
return 프로퍼티의_타입과_일치하는_유형의_표현식;
}
접근제한자 set
{
// value라는 문맥 키워드를 사용해 설정하려는 값을 표현
}
}
}
프로퍼티 정의에서는 매개변수가 없으므로 C# 컴파일러가 프로퍼티에 대입되는 값을 가리킬 수 없다는 문제가 발생한다. 이 문제를 해결하기 위해 별도로 set 블록 내부에서만 사용할 수 있는 'value' 예약어를 도입해 사용한다.
프로퍼티는 메서드의 특수한 변형에 불과하다. 프로퍼티는 C# 컴파일러가 빌드하는 시점에 자동으로 다음과 같은 메서드로 분리해서 컴파일한다. 프로퍼티는 접근자/설정자 메서드를 간편하게 만들어주는 도우미 성격의 구문이다.
ex)
class Car
{
int i_speed; // 정보은닉
public int Speed
{
get
{
return i_speed;
}
set
{
if(value > 150)
{
value = 150;
}
i_speed = value;
}
}
}
namespace _2020_06_01_002
{
class Program
{
static void Main(string[] args)
{
Car Mycar = new Car();
Mycar.Speed = 100;
Console.WriteLine("현재 속도 : 시속 {0}km", Mycar.Speed);
Mycar.Speed = 300;
Console.WriteLine("현재 속도 : 시속 {0}km", Mycar.Speed);
}
}
}
4) 상속(inheritance)
상속은 상위 객체는 자기가 가지고 있는 필드와 메서드를 하위 객체에게 물려주어 하위 객체가 사용할 수 있도록 하는 것을 말한다.
- 어떤 공통적인 특징이 있고 그 특징을 상송받아 다른 세부적인 항목을 정의
- 공통적인 특징을 정의하는 부모 클래스(parent class)를 두고 자식 클래스(child class)에서 부모의 기능을 물려받는 식으로 처리
- C#에서는 보다시피 콜론(':')을 이용해 부모 클래스의 기능을 물려받을 수 있고 실제로 상속받은 클래스는 부모의 속성과 행위를 접근 제한자 규칙에 따라 외부에 제공
- 자식 클래스일지라도 부모의 private 멤버에 접근하는 것은 허용되지 않음
- 외부에서의 접근은 차단하면서도 자식에게는 허용하고 싶다면 protected 접근 제한자를 사용
- 상속을 의도적으로 막고 싶을 때는 sealed 예약어를 사용
- C#은 단일 상속(single inheritance)만 지원
- 계층 상속은 가능하지만 다중 상속(multiple inheritance)을 받는 것은 허용하지 않음
sealed class Pen
{
}
public class ElectricPen : Pen // 컴파일 오류 발생
{
}
ex)
public class Computer
{
bool powerOn;
public void Boot()
{
Console.WriteLine("컴퓨터를 켭니다.");
}
public void Shutdown()
{
Console.WriteLine("컴퓨터를 끕니다.");
}
public void Reset()
{
Console.WriteLine("컴퓨터를 재부팅합니다.");
}
}
public class Notebook : Computer
{
bool fingerScan;
public bool HasFingerScanDevice()
{
return fingerScan;
}
}
public class Desktop : Computer
{
}
public class Netbook : Computer
{
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("==========노트북==========");
Notebook aNotebook = new Notebook();
aNotebook.Boot();
aNotebook.Reset();
aNotebook.Shutdown();
Console.WriteLine("==========데스크탑==========");
Desktop aDesktop = new Desktop();
aDesktop.Boot();
aDesktop.Reset();
aDesktop.Shutdown();
Console.WriteLine("==========넷북==========");
Netbook aNetbook = new Netbook();
` aNetbook.Boot();
aNetbook.Reset();
aNetbook.Shutdown();
}
}
4.1) 형변환
기본 자료형의 형 변환(암시적 형변환, 명시적 형변환)처럼 class로 정의된 타입의 부모/자식 관계에도 동일하게 적용
- 암시적 형변환 : 특수화 타입의 변수에서 일반화된 타입의 변수로 값이 대입되는 경우
- 명시적 형변환 : 일반화 타입의 변수에서 특수화된 타입의 변수로 값이 대입되는 경우
특수화 타입 인스턴스를 일반화 타입 변수로 대입하는 경우에는 암시적 형 변환이 가능하다. 클래스 간의 명시적 형변환보다는 암시적 형변환이 좀 더 자주 사용된다.
//1 암시적 형변환
Notebook notebook = new Notebook();
Computer pc1 = MyNotebook;
부모 클래스(일반화 타입)의 인스턴스를 자식 클래스(특수화 타입)의 변수로 대입하는 것은 암시적 변환이 불가능하다. 캐스팅 연산자를 사용해 명시적 형 변환은 가능하지만 오류가 발생한다.
//2
//Computer pc = new Computer();
//Notebook nb = pc; // 에러
//3 명시적 형변환, 컴파일은 가능
Computer pc = new Computer();
Notebook notebook = (Notebook)pc;
명시적 형 변환을 개발자가 의도적으로 원하는 경우도 있기 때문에 허용된다.
//4
Notebook noteBook = new Notebook();
Computer pc1 = noteBook; // 부모 타입으로 암시적 형변환
Notebook note2 = (Notebook)pc1; // 다시 본래 타입으로 명시적 형변환
ex)
public class Computer
{
protected bool powerOn;
public void Boot()
{
Console.WriteLine("컴퓨터를 컵니다.");
}
public void Shutdown()
{
Console.WriteLine("컴퓨터를 끕니다.");
}
public void Reset()
{
Console.WriteLine("컴퓨터를 재부팅합니다.");
}
}
public class Notebook : Computer
{
bool fingerScan;
public bool HasFingerScanDevice()
{
return fingerScan;
}
}
public class Desktop : Computer
{
}
public class Netbook : Computer
{
}
public class DeviceManager
{
public void TurnOff(Computer device)
{
device.Shutdown();
}
}
class Program
{
static void Main(string[] args)
{
Notebook aNotebook = new Notebook();
Desktop aDesktop = new Desktop();
Netbook aNetbook = new Netbook();
DeviceManager aDeviceManager = new DeviceManager();
aDeviceManager.TurnOff(aNotebook);
aDeviceManager.TurnOff(aDesktop);
aDeviceManager.TurnOff(aNetbook);
}
}
각 자식 클래스의 인스턴스를 부모 객체 배열에 담을 수 있다.
Computer[] machines = new Computer[] { new Notebook(), new Desktop(), new Netbook() }; // 암시적 형변환
//Computer[] machines;
//machines = new Computer[3];
//machines[0] = new Notebook();
//machines[1] = new Desktop();
//machines[2] = new Netbook();
DeviceManager aDeviceManager = new DeviceManager();
foreach(Computer cp in machines)
{
aDeviceManager.TurnOff(cp);
}
cf. Big-endian, Little-endian
메모리에 저장될 때 어떻게 저장되는가를 규정
- 1 Byte 단위로 순서가 뒤집힘
- Big-endian : 메모리에 저장될 때 상위 바이트가 먼저 저장(작은 주소가 먼저 할당), 숫자 크기 비교가 빠름, 소프트웨어의 디버그가 편함, 네트워크 바이트 오더에선 Big-endian이 가장 흔한 포맷
- Little-endian : 메모리에 저장될 때 하위 바이트가 먼저 저장, 수학적 연산이 쉬움, 타입을 읽거나 형 변환하는데 빠름
5) as, is 연산자
5.1) as 연산자
- 오류를 발생시키지 않고 형 변환이 가능한지 확인할 수 있는 방법
- 형변환이 가능하면 지정된 타입의 인스턴스 값을 반환하고, 가능하지 않으면 null을 반환하기 때문에 null 반환 여부를 통해 형변환이 성공했는지 판단할 수 있음
- 참조형 변수에 대해서만 적용할 수 있고 참조형 타입으로의 체크만 가능하다.
- 형 변환된 인스턴스가 필요할 경우 사용
ex)
Computer pc = new Computer();
Notebook notebook = pc as Notebook;
if(notebook != null) // 코드대로라면 if문 내부의 코드가 실행되지 않는다.
{
notebook.Shutdown();
}
ex) as의 잘못된 사용 예
int n = 5;
if((n as string) != null) // 컴파일 오류 발생
{
Console.WriteLine("변수 n은 string 타입");
}
string txt = "txt";
if((txt as int) != null) // 컴파일 오류 발생
{
Console.WriteLine("변수 txt는 int 타입");
}
5.2) is 연산자
- is 연산자는 형 변환의 가능성 여부를 불린형의 결괏값(true/false)으로 반환한다.
- 참조 형식뿐 아니라 값 형식에서도 사용할 수 있음(값 형식에 사용 시 컴파일 오류는 아니지만 경고는 발생)
- 형 변환된 인스턴스가 필요 없을 시 사용
ex)
int n = 5;
if(!(n is string))// false == (n is string)
{
Console.WriteLine("변수 n은 string 타입이 아닙니다");
}
string txt = "text";
if((txt is int) == false)
{
Console.WriteLine("변수 txt는 int 타입이 아닙니다.");
}
'스마트팩토리 > C#' 카테고리의 다른 글
11. 다형성 (0) | 2020.06.03 |
---|---|
10. Object, Array, this, base, 다형성 (0) | 2020.06.02 |
8. 종료자, static, 네임스페이스 (0) | 2020.05.29 |
7. 클래스 (0) | 2020.05.28 |
6. 객체지향, 구조체, foreach, 배열 (0) | 2020.05.27 |