Concepts
- 규정대로 하는 프로그래밍. 일종의 코딩 컨벤션.
- 클래스 내에 기본 생성자, 복사 생성자, 대입 연산자 오버로드, 소멸자를 반드시 정의해야 함.
기본 생성자 Default Constructor
- 별도로 생성자를 구현하지 않을 시 사용되는 생성자. 매개 변수 없음.
- 멤버 변수가 0, NULL 등으로 초기화 됨.
복사 생성자 Copy Contstuctor
Fixed::Fixed(const Fixed& fixed)
- 다른 인스턴스의 참조자(Reference)를 인수로 받아, 그 참조를 이용해 자신의 인스턴스를 초기화 함.
- 기존 값을 복사하여 전달해 주므로 const로 선언 (값이 바뀌면 안 됨)
얕은 복사 Shallow Copy
- 객체를 복사할 때 해당 객체만 복사하여 새 객체를 생성
- 복사된 객체의 인스턴스 변수는 원본 객체의 인스턴스 변수와 같은 메모리 주소를 참조
- 해당 메모리 주소의 값이 변경되면 원본 객체, 복사 객체의 인스턴스 변수 값이 함께 변경됨
깊은 복사 Deep Copy
- 객체를 복사할 때 해당 객체와 인스턴스 변수까지 모두 복사
- 전부를 복사하여 새 객체에 담음
- 참조를 공유하지 않으며, 기존의 복사한 인스턴스와 다른 메모리 공간에 할당되어 독립적
소멸자 Destructor
- 객체의 수명이 끝났을 때 (사용을 다했을 때) 객체를 제거하기 위한 목적으로 사용됨
- 객체의 수명이 끝나면 컴파일러가 자동으로 소멸자 함수를 호출
- 클래스명과 동일하며, ~기호를 앞에 붙여 사용
오버로드 Overload
- C++에서는 함수의 이름이 같아도 매개변수가 다르면 선언 및 정의가 가능함
- 오버로드는, 같은 이름을 가진 복수의 객체가 각각 다른 기능을 하도록 만드는 것
연산자 오버로딩 Operators Overload
- 기존에 사용되던 연산자의 기능을 재정의함
- 많은 언어에서 그렇듯, 객체끼리
+
, -
, /
, *
등의 연산자를 사용하여 연산하는 것은 불가능
- 연산자 오버로딩을 통해 연산자의 기존 기능을 재정의 해 준다면, 객체 또한 기본 자료형 변수 (데이터 타입)처럼 덧셈, 곱셈, 뺄셈, 나눗셈 등의 연산이 가능하게 만들 수 있음
- 오버로딩 된 연산자의 피연산자 중 하나는 사용자 정의 자료형 이어야 한다
연산자 오버로딩 방법
Fixed& operator=(const Fixed& fixed);
operator 키워드 바로 뒤에 연산자를 붙여 어떤 연산자를 오버로딩 할 것인지 정의.
클래스 내부에 위와 같은 연산자 오버로딩을 선언하면, 클래스 내의 멤버 함수에서 오버로딩 된 연산자 =
을 사용할 수 있음.
위와 같이 연산자 오버로딩을 클래스 내에 선언했을 때,
아래와 같이 복사 생성자를 사용해 fixed를 만들었다고 하면,
Fixed::Fixed(const Fixed& fixed)
{
std::cout << "Copy constructor called" << std::endl;
*this = fixed;
}
*this = fixed;
는, 어떤 객체의 주소값을 가리키는 *this
를 대상으로, 새로 정의된 operator=
함수를 호출하여, 피연산자 객체 fixed
를 전달한다. (복사 생성자를 통해 만들어진 새로운 객체).
만약 operator=
을 클래스 내에 정의하지 않은 상태였다면, 디폴트 대입 생성자가 생기고, 디폴트 대입 생성자는 얕은 복사를 한다. 대입 생성자 내에서 동적 할당을 하거나 깊은 복사가 필요하다면, 직접 생성자 오버로딩을 정의해야 한다.
연산자 오버로딩 호출 시점
- 복사 생성자와 대입 연산자 오버로딩은 유사하지만 호출되는 시점이 다르다.
- 복사 생성자는 객체가 새로 생성되는 시점에서 대입을 할 때 호출된다.
- 대입 연산자 오버로드는 객체 두 개가 이미 생성, 초기화를 마친 상태에서, 올바른 인자를 대입할 때 호출된다.
- 연산자 오버로딩 함수의 매개변수를 특정 객체로 선언했다면, 대입 연산자 오른쪽에 해당 객체가 들어왔을 경우에만 연산자 오버로딩이 실행된다.
Fixed point numbers (고정 소수)
참고1
참고2
- 소수점이 붙어 있는 수를 2진수로 변환하는 과정에서, 10진수를 2빈수로 바꾼 결과를 그대로 대입
- 특정 숫자의 소수점의 위치를 고정하는 방식
- 컴퓨터 언어에서 데이터 타입은 항상 최대 길이가 고정되어 있음
- 구현하기 편리하지만 범위의 정밀도가 낮아 소규모 시스템에서 간혹 쓰인다고 한다
이를테면 32Bit 운영체제에서, int형의 크기는 32비트 이므로, 앞의 10개의 비트는 정수 부분을, 나머지 22개의 비트는 소수점 이하 부분을 표현하도록 점의 위치를 고정.
소수점 위치를 어디로 설정해야 하는지에 대해서는 정해진 답이 없으며, 사용자 임의대로 설정할 수 있음.
(다만, 사용하는 수의 범위를 고려하여, 오버플로우가 발생하지 않도록 설정해야 함)
전체 비트의 수를 WL(Word Length)라고 할 때, 부호를 표현하는 맨 앞의 한 비트를 제외하면,
IWL (Integer Word Length, 정수 부분을 표현하는 비트 수)와 FWL (Fractionl Word Length, 소수점 이하 부분을 표현하는 비트 수) 의 관계는 FWL = WL - 1 - IWL 이다.
즉, 고정 소수점 정의를 위한 파라미터로 WL, IWL을 고려할 수 있다.
7.625라는 실수를 2진수로 변환하여 111.101이 되었다면, 16비트 체계에서 정수의 경우 소수점의 위치 기반으로 뒤에서부터, 소수부의 경우 앞에서부터 채우며 남는 뒷자리는 0으로 채움.
고정소수값으로 변환하는 방법
- 2진 정수 또는 부동소수값의 소수 부분을 넣을 비트 수를 정해두고 수를 표현
- 우리 과제에서는 Fractional Bits (소수부가 될 비트 칸 수)가 8비트로 정해져 있음
- 32비트 체계에서라면 앞의 24비트를 정수부로, 8비트를 소수부로 표현하는 것 과 같음
- 따라서 임의의 2진 정수 N을 고정 소수 값으로 표현하고, 소수부를 8비트로 고정할 경우,
- 앞으로 8비트만큼
<<
(비트 시프트 연산)을 해 주어야 함
비트 시프트 연산
Fractional Bits가 8일 경우의 공식들
정수 N -> 고정소수값
N << 8
N * 256
고정소수값 -> 정수값
fixed_point_number >> 8
fixed_point_number / 256
고정소수값 -> 실수
(float)fixed_point_number / (1 << 8)
(float)(fixed_point_number / 256)
Float point numbers (부동 소수)
- 10진수를 2진수로 변환한 결과를 그대로 넣는 게 아니라 몇 가지 과정을 거침
- 정수부에 1만 남을 때 까지 소수점을 왼쪽으로 이동시키고, 이동한 칸 수 만큼 아래 식의 n자리에 넣는다.
1.xxxxx... * 2&n
- 지수부는 어차피 1이니 상관 없지만, 127이라는 Bias를 더해준 값을 2진수로 변환하여 채운다. (자세한 설명은 참고1 블로그 확인)
차이점?
- 고정 소수점 산술이 부동 소수점 산술보다 훨씬 빠르다
- Fixed point is a simple yet very powerful way to represent fractional numbers in computer.
Exercises
ex00
- C++은 고정소수점을 갖고 있지 않으므로, 직접 만들어 보자.
- 위에 말한 Canonical Form 지키면서.
- Fixed 라는 클래스를 정의하고, 아래와 같은 멤버 변수/멤버 함수들을 가져야 한다.
// private members
// fixed point 값이 저장될 정수형 변수
// 항상 8의 값을 가지는 fractional bits가 저장될 static 정수형 상수.
// public members
// 0으로 초기화시키는 기본 생상자
// 소멸자
// 복사 생성자
// 대입 연산자 오버로딩 (assignation operator overload)
// getRawBits : raq value값을 단순히 반환하는 함수 (const)
// setRawBits : raw value값을 변경하는 함수
- 주어진 메인 문을 컴파일했을 때 주어진 결과가 나오도록 프로그램을 작성해라
기본 생성자, 복사 생성자, 대입 연산자, 각각의 멤버 함수들, 소멸자의 개념을 잘 알고 있는지,
프로그램 내에서 잘 호출되고 작동되고 있는지를 묻는 문제.
ex01
- 위에서 만든 Fixed 클래스를 재사용해서 다음과 같은 애들을 추가해라.
- 상수형 10진 정수를 파라미터로 받는 생성자. 이 정수를 상응하는 fixed(8) 고정 소수값으로 바꾸는 아이.
- 상수형 실수를 파라미터로 받는 생성자. 이 실수를 상응하는 fixed(8) 고정 소수값으로 바꾸는 아이.
float toFloat(void) const
멤버 함수. 고정 소수값을 실수값으로 바꾸는 아이.
int toInt(void) const
멤버 함수. 고정 소수값을 10진 정수형으로 바꾸는 아이.
- 헤더에
<<
연산자 오버로딩. 고정 소수값의 실수형 표현을 출력하기 위해.