article thumbnail image
Published 2021. 1. 25. 12:32

구조체(Struct)

객체를 표현하기 위해 하나 이상의 변수가 필요한 프로그래밍 사례가 많이 있다. 예를 들어, 자신의 표현하기 위해 이름, 생일, 키 , 몸무게 또는 자신에 대한 기타 특성을 저장할 수 있다.

std::string myName; 
int myBirthYear; 
int myBirthMonth;
int myBirthDay; 
int myHeightInches; 
int myWeightPounds;

위에는 어떻게든 그룹화하지 않은 6개의 독립 변수가 있다. 자신에 대한 정보를 함수에 전달하려면 각 변수를 개별적으로 전달해야 합니다. 또한, 다른 사람에 대한 정보를 저장하려면 추가된 사람마다 6개의 변수를 추가로 선언해야 합니다.

다행히도 C++에서는 고유한 사용자 정의 집계 데이터 유형(user-defined aggregate data type)을 생성할 수 있습니다.

집계 데이터 유형은 여러 개별 변수를 함께 그룹화하는 데이터 유형이다. 가장 단순한 집계 데이터 유형 중 하나가 구조체(struct)다.

 

즉, 구조체는 하나 이상의 변수를 그룹지어서 새로운 자료형을 정의하는 것이다.

 

구조체 선언 및 정의(Declaring and defining structs)

구조체는 사용자 정의 자료형이기 때문에, 먼저 그것을 사용하기 전에 구조체가 어떻게 생겼는지 컴파일러에 말해야 한다. 이를 위해 struct 키워드를 사용해 구체를 선언해야 한다.

struct Employee 
{ 
   short id; 
   int age; 
   double wage; 
};

 

위 코드는 컴파일러에 Employee 구조체를 정의한다고 말한다. Employee 구조체는 세 개의 변수를 포함한다. (id, age, wage) 구조체의 일부인 이러한 변수를 멤버(member) 또는 필드(field)라고 한다.

Employee는 단지 선언에 불과하다. 컴파일러에 구조체가 멤버 변수가 있을것이라고 말하고 있지만, 지금은 어떤 메모리도 할당되지 않는다. 일반적으로 구조체 이름은 대문자로 시작하여 변수 이름과 구분한다.

 

경고 : C++에서 가장 쉬운 실수 중 하나는 구조체 선언 끝에 세미콜론을 잊어버리는 것이다.

 

Employee 구조체를 사용하려면 Employee 타입의 변수를 선언하면 된다.

Employee joe; // 구조체 Employee는 대문자로 시작하고, 변수 joe는 소문자로 시작한다.

위 코드는 joe라는 구조체 Employee 타입의 변수를 정의한다. 일반 변수와 마찬가지로 구조체 변수를 정의하면 해당 변수에 대한 메모리가 할당된다.

구조체 멤버 접근(Accessing struct members)

Employee joe와 같은 변수를 정의할 때, 변수 joe는 멤버 변수를 포함하는 전체 구조체를 참조한다. 개별 멤버에 접근하기 위해 멤버 선택 연산자(member selection operator : .)를 사용하면 된다.

다음은 구성원 멤버 선택 연산자를 사용하여 각 멤버 함수를 초기화하는 예제다.

Employee joe; // create an Employee struct for Joe 
joe.id = 14; // assign a value to member id within struct joe 
joe.age = 32; // assign a value to member age within struct joe 
joe.wage = 24.15; // assign a value to member wage within struct joe 
Employee frank; // create an Employee struct for Frank 
frank.id = 15; // assign a value to member id within struct frank 
frank.age = 28; // assign a value to member age within struct frank 
frank.wage = 18.27;// assign a value to member wage within struct frank

 

일반 변수처럼 구조체 멤버 변수도 초기화되지 않고 쓰레기값이 들어간다. 그러므로 수동으로 초기화해야 한다.

구조체 멤버 변수는 일반 변수와 같게 작동한다.

int totalAge = joe.age + frank.age; 
if (joe.wage > frank.wage) std::cout << "Joe makes more than Frank\n"; 
else if (joe.wage < frank.wage) std::cout << "Joe makes less than Frank\n"; 
else std::cout << "Joe and Frank make the same amount\n"; // Frank got a promotion 
frank.wage += 2.50; // Today is Joe's birthday 
++joe.age; // use pre-increment to increment Joe's age by 1

 

구조체 초기화(Initializing structs)

멤버별로 값을 지정하여 구조체를 초기화하는 작업은 매우 번거로우므로 C++은 초기화 목록(initializer list)을 사용하여 구조체를 초기화하는 더 빠른 방법을 지원한다. 이렇게 하면 선언 시간에 구조체의 일부 또는 전체 멤버 변수를 초기화 할 수 있다.

struct Employee 
{ 
   short id; int age; double wage; 
}; 

Employee joe = { 1, 32, 60000.0 }; // joe.id = 1, joe.age = 32, joe.wage = 60000.0
Employee frank = { 2, 28 }; // frank.id = 2, frank.age = 28, frank.wage = 0.0 (default initialization)

C++ 11에서는 유니폼 초기화(uniform intialization)를 사용할 수도 있다.

Employee joe { 1, 32, 60000.0 }; // joe.id = 1, joe.age = 32, joe.wage = 60000.0 
Employee frank { 2, 28 }; // frank.id = 2, frank.age = 28, frank.wage = 0.0 (default initialization)

 

초기화 목록에 일부 멤버의 초기값이 포함되어 있지 않으면 해당 멤보는 기본(default)값으로 초기화된다. 위의 예제에서는 frank.wage에 명시적으로 초기값을 지정하지 않았기 때문에 frank.wage가 0.0으로 초기화된다.

C++11/14 : None-static member initialization

C++11 부터는 비-정적(non-static) 멤버 변수에 기본값을 저장할 수 있다.

struct Rectangle 
{ 
   double length = 1.0; 
   double width = 1.0; 
}; 

int main() 
{ 
   Rectangle x; // length = 1.0, width = 1.0 
   x.length = 2.0; // you can assign other values like normal 
   return 0; 
}

그러나 불행하게도, 멤버 초기화 구문이 멤버 초기화 목록 및 유니폼 초기화와 호환되지 않는다. 예를 들어, C++ 11에서는 다음 프로그램이 컴파일되지 않는다.

struct Rectangle 
{ 
   double length = 1.0; // non-static member initialization 
   double width = 1.0; 
}; 

int main() 
{ 
   Rectangle x{ 2.0, 2.0 }; // uniform initialization 
   return 0; 
} 

// Compile Error!

따라서 C++ 11에서는 비-정적(non-static) 멤버 초기화와 유니폼 초기화중 무엇을 사용해야 할지 정해야 한다.

그러나 C++ 14에서는 이 제한이 해제되어 두 가지 모두 사용할 수 있다. 둘 다 사용하면 초기화 목록/유니폼 초기화를 우선한다.

'DevLog > C & C++' 카테고리의 다른 글

포인터(Pointer)와 레퍼런스(Reference)  (0) 2021.03.01
C++ 포인터 개념  (0) 2021.02.04
C++ STL 맵 기본 사용법과 예제  (0) 2021.01.24
C++ 오버로딩과 오버라이딩  (0) 2021.01.24
C++ 가비지 컬렉션, 참조 카운트  (0) 2021.01.24
복사했습니다!