06
01

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
COMMENT