1. 상수 (const)
체스 프로그램을 작성할 때 각 말의 종류를 int 타입의 상수(변하지 않는 수)로 표현한다고 하면
const란 키워드를 붙이면 그 값이 변하지 않게 만들 수 있다.
const int PieceTypeKing = 0;
const int PieceTypeQueen = 1;
const int PieceTypeRook = 2;
const int PieceTypePawn = 3;
// 기타
int myPiece = PieceTypeKing;
PieceTypeKing의 값을 다음과 같이 바꾸려고 한다면 오류가 발생하여 값을 바꾸지 못하게 할 수 있다.
const int PieceTypeKing = 0;
PieceTypeKing = 4;
이렇게 표현해도 되지만 위험한 상황이 발생할 수 있다.
myPiece를 일반 int 값으로 표현했기 때문에 myPiece 값을 증가시키는 코드를 작성할 수도 있기 때문이다.
킹을 나타내는 값에 1을 더하면 퀸이 될 수 있고 다른 말로도 바뀔 가능성이 있기 때문이다.
2. 열거 타입 (enum)
열거 타입(enum)을 사용하면 숫자를 나열하는 방식과 범위를 마음대로 정의해서 변수를 선언하는데 활용할 수 있다.
이때 enum 타입을 적용하면 변수에 지정할 수 있는 값의 범위를 엄격하게 제한하기 때문에 이런 문제를 방지할 수 있다.
변수가 네 가지 말에 해당하는 값만 가질 수 있도록 제한하고 싶다면 PieceType이라는 enum 타입을 새로 정의한다.
enum PieceType { PieceTypeKing, PieceTypeQueen, PieceTypeRook, PieceTypePawn };
enum 타입을 구성하는 멤버는 내부적으로 정숫값으로 표현된다.
PieceTypeKing에 실제로 할당된 값은 0이다.
PieceType 변수에 대해 사칙연산을 수행하거나 일반 정숫값처럼 다루는 코드를 작성하면 컴파일 오류가 발생한다.
PieceType myPiece;
myPiece = 0;
enum 타입을 정의할 때 각 멤버에 해당하는 정수 값을 직접 지정할 수도 있다.
enum PieceType { PieceTypeKing = 1, PieceTypeQueen, PieceTypeRook = 10, PieceTypePawn };
여기서 PieceTypeKing은 정숫값 1을 갖고, PieceTypeQueen은 컴파일러에 의해 2라는 값이 대입된다.
enum 타입의 멤버에 값을 직접 대입하지 않으면 컴파일러가 이전 멤버의 값에서 1을 증가시킨 값으로 알아서 대입한다.
enum 타입의 첫 번째 멤버의 값을 생략하면 컴파일러는 0을 대입한다.
3. 엄격한 열거 타입 (enum class)
enum은 원래 타입을 엄격히 따지지 않는다.
타입을 엄격히 따지는 것을 '스트롱 타입' 또는 '타입에 안전하다(타입 세이프하다)'고 표현한다.
enum은 항상 정수로 해석하기 때문에 선언한 형태에 관계없이 모든 enum 타입을 서로 비교할 수 있다.
타입을 엄격하게 적용하고 싶다면 enum class를 사용한다.
enum으로 선언한 PieceType을 타입 세이프 버전으로 정의할 수 있다.
enum class PieceType
{
King = 1,
Queen,
Rook = 10,
Pawn
};
enum class로 정의한 열거 타입 값들의 이름은 스코프(유효 범위)가 자동으로 확장되지 않는다.
enum class 스코프 안에서만 유효하다.
따라서 열거 타입 값을 사용할 때마다 스코프 지정 연산자(::)를 붙여야 한다.
PieceType piece = PieceType::King;
이는 열거 타입 값의 이름을 짧게 부를 수 있다는 뜻이기도 하다.
enum class로 정의한 열거 타입 값은 자동으로 정수 타입으로 변환되지 않는다.
그래서 이런 표현은 불가능하다.
if (PieceType::Queen == 2) { ... }
다음과 같이 명시적으로 형 변환해야 한다.
if (static_cast<int>(PieceType::Queen) == 2)
기본적으로 열거 타입의 값은 정수 타입으로 저장된다.
하지만 다음과 같이 내부 표현 타입을 바꿀 수 있다.
enum class PieceType : unsigned long
{
King = 1,
Queen,
Rook = 10,
Pawn
};
4. 구조체 (struct)
구조체를 사용하면 기존에 정의된 타입을 한 개 이상 묶어서 새로운 타입으로 정의할 수 있다.
직원 정보 관리 시스템을 구축하려면 각 직원의 성, 이름, 직원번호 등의 정보를 저장해야 한다.
이 모든 정보는 employeestruct.h란 헤더 파일에 다음과 같이 구조체를 정의하는 방식으로 표현 가능하다.
struct Employee {
char firstInitial;
char lastInitial;
int employeeNumber;
int salary;
};
Employee 타입으로 선언한 변수는 이 구조체에 있는 모든 필드를 가진다.
구조체를 구성하는 각 필드는 도트(.) 연산자로 접근한다.
다음 코드는 직원에 대한 레코드를 생성한 뒤 그 결과를 화면에 출력하는 예이다.
#include <iostream>
#include "employeestruct.h"
using namespace std;
int main()
{
// 직원 레코드 생성 및 값 채우기
Employee anEmployee;
anEmployee.firstInitial = 'M';
anEmployee.lastInitial = 'G';
anEmployee.employeeNumber = 42;
anEmployee.salary = 80000;
// 직원 레코드에 저장된 값 출력하기
cout << "Employee: " << anEmployee.firstInitial << anEmployee.lastInitial << endl;
cout << "Number: " << "Number: " << anEmployee.employeeNumber << endl;
cout << "Salary: $" << anEmployee.salary << endl;
return 0;
}
결과
'💻프로그래밍 내용 정리 > C++17' 카테고리의 다른 글
[C++ 1.1.8] 논리 연산자(<, <=, >, >=, ==, !=, !, &&, ||), 단락 논리 (0) | 2022.08.15 |
---|---|
[C++ 1.1.7] 조건문(if/else/switch), 이니셜라이저, 폴스루(fallthrough), 조건 연산자 (0) | 2022.08.15 |
[C++ 1.1.5] 연산자(단항, 이항, 비트 연산자) (0) | 2022.08.15 |
[C++ 1.1.4] 변수, 캐스팅(동적 형변환, static_cast) (0) | 2022.08.15 |
[C++ 1.1.3] 리터럴 (0) | 2022.08.15 |