C++ 에서 구조체 변수의 선언


C와 C++에서 구조체 변수를 선언하는 방법은 다음과 같다.


 C

C++ 

 

 struct Car basicCar ;

 struct Car simpleCar ;

 

 Car basicCar ;

 Car simple car ; 


C언어에서 앞에 삽입된 struct는 이어서 선언되는 자료형이 구조체를 기반으로 정의된 자료형임을 나타낸다. 그리고 키워드 struct를 생략하려면 별도의 typedef 선언을 추가해야 된다. 


하지만 C++에서는 기본 자료형 변수의 선언방식이나 구조체를 기반으로 정의된  자료형의 변수 선언방식에 큰 차이가 없다. 즉 C++에서는 별도의 typedef 선언 없이도 변수를 선언할 수 있다.


앞서 정의한 구조체를 기반으로 예제를 작성해보자.


  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. #define ID_LEN 20  
  5. #define MAX_SPD 200  
  6. #define FUEL_STEP 2  
  7. #define ACC_STEP 10  
  8. #define BRK_STEP 10  
  9.   
  10. struct Car  
  11. {  
  12.     char gamerID[ID_LEN];  
  13.     int fuelGauge;  
  14.     int curspeed;  
  15. };  
  16. void ShowCarState(const Car &car) {  
  17.     cout << "userID: " << car.gamerID << endl;  
  18.     cout << "gauge : " << car.fuelGauge << "%" << endl;  
  19.     cout << "speed : " << car.curspeed << "km/s" << endl;  
  20. }  
  21.   
  22. void Accel(Car &car) {  
  23.     if (car.fuelGauge <= 0)  
  24.         return;  
  25.   
  26.     else  
  27.         car.fuelGauge -= FUEL_STEP;  
  28.   
  29.     if (car.curspeed + ACC_STEP >= MAX_SPD) {  
  30.         car.curspeed = MAX_SPD;  
  31.         return;  
  32.     }  
  33.   
  34.     car.curspeed += ACC_STEP;  
  35. }  
  36.   
  37. void Break(Car &car) {  
  38.     if (car.curspeed < BRK_STEP) {  
  39.         car.curspeed = 0;  
  40.         return;  
  41.     }  
  42.   
  43.     car.curspeed = BRK_STEP;  
  44. }  
  45.   
  46. int main() {  
  47.     Car run99 = { "run99",100,0 };  
  48.     Accel(run99);  
  49.     Accel(run99);  
  50.     ShowCarState(run99);  
  51.     cout << endl;  
  52.     Break(run99);  
  53.     ShowCarState(run99);  
  54.     cout << endl;  
  55.     Car speed77 = { "speed77",100,0 };  
  56.     Accel(speed77);  
  57.     Break(speed77);  
  58.     ShowCarState(speed77);  
  59.       
  60.     return 0;  
  61. }  


[ 결과 ]




  • 4~8행 : 구조체 Car와 관련된 각종 정보를 상수화
  • 16행 : 차의 정보를 출력하는 기능의 함수이다. 단순 정보만 출력하기 때문에 const 참조자를 사용하였다.
  • 22행 : 차의 가속을 위해서 엑셀을 밟은 상황을 표현해 놓은 함수.
  • 37행 : 브레이크를 밟은 상황을 표현한 함수. 단순히 속도가 감속하는것만 표현
  • 47행 : 구조체 변수의 선언 및 초기화가 진행.
  • 48~49행 : 엑셀과 브레이크를 밟은 상황을 연출하고 있다.

위의 선언된 3개의 함수에 대해서 다음과 같이 이야기할 수 있다.

구조체 Car과 함께 부류를 형성하여, Car과 관련된 데이터의 처리를 담당하는 함수


따라서 위의 함수들은 구조체 Car에 종속적인 함수들이라고 할 수 있다. 

하지만 전역함수의 형태를 띠기 때문에, 이 함수들이 구조체 Car에 종속적임을 나타내지 못한다. 

따라서 다른 영역에서 이 함수를 호출하는 실수가 발생할 수 있다.


 

구조체 안에 함수 삽입하기


구조체 속에 종속적인 함수들을 구조체 안에 함께 묶어버리면 관련된 데이터와 함수를 모두 묶을 수 있다.

위의 예제를 이용하여 묶어보자.


  1. struct Car  
  2. {  
  3.     char gamerID[ID_LEN];  
  4.     int fuelGauge;  
  5.     int curspeed;  
  6.   
  7.     void ShowCarState() {  
  8.         cout << "user ID : " << gamerID << endl;  
  9.         cout << "gauge   : " << fuelGauge << "%" << endl;  
  10.         cout << "speed   : " << curspeed << "km/s" << endl;  
  11.     }  
  12.   
  13.     void Accel() {  
  14.         if (fuelGauge <= 0)  
  15.             return;  
  16.         else  
  17.             fuelGauge -= FUEL_STEP;  
  18.   
  19.         if (curspeed + ACC_STEP >= MAX_SPD) {  
  20.             curspeed = MAX_SPD;  
  21.             return;  
  22.         }  
  23.   
  24.         curspeed += ACC_STEP;  
  25.     }  
  26.   
  27.     void Break() {  
  28.         if (curspeed < BRK_STEP) {  
  29.             curspeed = 0;  
  30.             return;  
  31.         }  
  32.   
  33.         curspeed = BRK_STEP;  
  34.     }  
  35. };  


구조체 안에 삽입된 함수의 정의에 어떠한 변화가 생겼는지, ShowCarState 함수를 예로 확인해보자.


  1. void ShowCarState()   
  2. {  
  3.     cout << "user ID : " << gamerID << endl;  
  4.     cout << "gauge   : " << fuelGauge << "%" << endl;  
  5.     cout << "speed   : " << curspeed << "km/s" << endl;  
  6. }  


이렇 듯 연산의 대상에 대한 정보가 불필요한 이유는, 함수가 구조체 내에 삽입되면서 구조체 내에 선언된 변수에 직접 접근이 가능해졌기 때문이다. 따라서 다음과 같이 구조체 변수를 각각 선언하면,


Car run99 = { "run99" , 100 , 0 } ;

Car speed77 = { "speed77" , 100 . 0 } ;


다음의 형태로 구조체 변수가 생성된다.


run99

speed77 

 

 char gamerID[ ID_LEN ] ;

 int fuelGauage ;

 int curspeed ;


 char gamerID[ ID_LEN ] ;

 int fuelGauage ;

 int curspeed ;

 void ShowCarState( )

 {

     . . . . .

 }

 void Accel( )

 {

     . . . . .

 }

 void Break( )

 {

     . . . . .

 }

 void ShowCarState( )

 {

     . . . . .

 }

 void Accel( )

 {

     . . . . .

 }

 void Break( )

 {

     . . . . .

 }


참고로 위 그림에서는 모든 구조체 변수 내에 함수가 각각 별도로 존재하는 것처럼 묘사해 놓았다.

실제로는 모든 Car 구조체 변수가 하나의 함수를 공유한다.

다만, 논리적으로 각각 변수가 자신의 함수를 별도로 지나는 것과 가은 효과 및 결과를 보이기 때문에

C++의 구조체 변수는 위 그림의 형태로 이해하는 것이 좋다. 예제를 통해 확인해보자.


  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. #define ID_LEN 20  
  5. #define MAX_SPD 200  
  6. #define FUEL_STEP 2  
  7. #define ACC_STEP 10  
  8. #define BRK_STEP 10  
  9.   
  10. struct Car  
  11. {  
  12.     char gamerID[ID_LEN];  
  13.     int fuelGauge;  
  14.     int curspeed;  
  15.   
  16.     void ShowCarState() {  
  17.         cout << "user ID : " << gamerID << endl;  
  18.         cout << "gauge   : " << fuelGauge << "%" << endl;  
  19.         cout << "speed   : " << curspeed << "km/s" << endl;  
  20.     }  
  21.   
  22.     void Accel() {  
  23.         if (fuelGauge <= 0)  
  24.             return;  
  25.         else  
  26.             fuelGauge -= FUEL_STEP;  
  27.   
  28.         if (curspeed + ACC_STEP >= MAX_SPD) {  
  29.             curspeed = MAX_SPD;  
  30.             return;  
  31.         }  
  32.   
  33.         curspeed += ACC_STEP;  
  34.     }  
  35.   
  36.     void Break() {  
  37.         if (curspeed < BRK_STEP) {  
  38.             curspeed = 0;  
  39.             return;  
  40.         }  
  41.   
  42.         curspeed = BRK_STEP;  
  43.     }  
  44. };  
  45.   
  46. int main() {  
  47.     Car run99 = { "run99",100,0 };  
  48.     run99.Accel();  
  49.     run99.Accel();  
  50.     run99.ShowCarState();  
  51.     cout << endl;  
  52.     run99.Break();  
  53.     run99.ShowCarState();  
  54.     cout << endl;  
  55.     Car speed77 = { "speed77",100,0 };  
  56.     speed77.Accel();  
  57.     speed77.Break();  
  58.     speed77.ShowCarState();  
  59.       
  60.     return 0;  
  61. }  



결과는 위와 동일하다.


문제


2차원 평면상에서의 좌표를 표현할 수 있는 구조체를 다음과 같이 정의하였다.


struct Point

{

int xpos ; 

int ypos ;

} ;


위의 구조체를 기반으로 다음의 함수를 정의하고자 한다 

(자세한 기능은 실행의 예를 통해서 확인하도록 한다.)


void MovePos ( int x, int y ) ;

void AddPoint( const Point &pos ) ;

void ShowPosition( ) ;


단, 위의 함수들은 구조체 안에 정의를 해서 다음의 형태로 main( ) 함수를 구성할 수 있어야 한다.


  1. int main()  
  2. {  
  3.    Point pos1 = {12, 4};  
  4.    point pos2 = {12, 30};  
  5.   
  6.    pos1.MovePos(-7, 10);  
  7.    pos1.ShowPosition();  
  8.   
  9.    pos1.AddPoint(pos2);  
  10.    pos1.showPosition();  
  11.   
  12.    return 0;  
  13. }  



실행 예





  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. struct Point  
  5. {  
  6.     int xpos;  
  7.     int ypos;  
  8.   
  9.     void MovePos(int x, int y) {  
  10.         xpos += x;  
  11.         ypos += y;  
  12.     }  
  13.   
  14.     void AddPoint(const Point &pos) {  
  15.         xpos += pos.xpos;  
  16.         ypos += pos.ypos;  
  17.     }  
  18.     void ShowPosition() {  
  19.         cout << "[" << xpos << ", " << ypos << "]" << endl;  
  20.     }  
  21. };  
  22.   
  23. int main()   
  24. {  
  25.     Point pos1 = { 12,4 };  
  26.     Point pos2 = { 20,30 };  
  27.   
  28.     pos1.MovePos(-7, 10);  
  29.     pos1.ShowPosition();  
  30.   
  31.     pos1.AddPoint(pos2);  
  32.     pos1.ShowPosition();  
  33.   
  34.     return 0;  
  35.   
  36. }  



구조체 안에 enum 상수의 선언


위에서 사용되었던 예제들을 살펴보면 다음의 매크로 상수들이 존재한다.


  1. #define ID_LEN 20  
  2. #define MAX_SPD 200  
  3. #define FUEL_STEP 2  
  4. #define ACC_STEP 10  
  5. #define BRK_STEP 10  


그런데 이들 상수 역시 구조체 Car에게만 의미가 있는 상수들이다. 즉, 다른영역에서 사용하도록 정의된 상수가 아니니 이들 상수도 구조체 내에 포함시키는 것이 좋을 수 있다. 따라서 이러한 경우 열거형 enum을 이용해서 다음과 같이 구조체 내에서만 유효한 상수를 정의하면 된다.


  1. struct Car  
  2. {  
  3.     enum{  
  4.         ID_LEN 20  
  5.         MAX_SPD 200  
  6.         FUEL_STEP 2  
  7.         ACC_STEP 10  
  8.         BRK_STEP 10  
  9.     }  
  10. };  



enum의 선언을 구조체 내부에 삽입하는 것이 부담스럽다면, namespace를 이용해서 상수가 사용되는 영역을 명시하는 것도 또 다른 방법이 될 수 있다. namespace를 사용하면 몇몇 구조체들 사이에서만 사용하는 상수들을 선언할 때 특히 도움이 되며, 위에서 보인 방법보다 기독성도 좋아지는 경향이 있다. 예제를 통해 확인해보자.


  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. namespace CAR_CONST  
  5. {  
  6.     enum {  
  7.         ID_LEN = 20,  
  8.         MAX_SPD = 200,  
  9.         FUEL_STEP = 2,  
  10.         ACC_STEP = 10,  
  11.         BRK_STEP = 10  
  12.     };  
  13. }  
  14.   
  15. struct Car  
  16. {  
  17.     char gamerID[CAR_CONST::ID_LEN];  
  18.     int fuelGuage;  
  19.     int curSpeed;  
  20.   
  21.     void ShowCarState() {  
  22.         cout << "user ID : " << gamerID << endl;  
  23.         cout << "Gage    : " << fuelGuage << "%" << endl;  
  24.         cout << "speed   : " << curSpeed << "km/s" << endl;  
  25.     }  
  26.     void Accel() {  
  27.         if (fuelGuage == 0)  
  28.             return;  
  29.         else  
  30.             fuelGuage -= CAR_CONST::FUEL_STEP;  
  31.   
  32.         if ((curSpeed + CAR_CONST::ACC_STEP) >= CAR_CONST::MAX_SPD) {  
  33.             curSpeed = CAR_CONST::MAX_SPD;  
  34.             return;  
  35.         }  
  36.   
  37.         curSpeed += CAR_CONST::ACC_STEP;  
  38.     }  
  39.     void Break() {  
  40.         if (curSpeed < CAR_CONST::BRK_STEP) {  
  41.             curSpeed = 0;  
  42.             return;  
  43.         }  
  44.         curSpeed -= CAR_CONST::BRK_STEP;  
  45.     }  
  46. };  
  47.   
  48. int main()  
  49. {  
  50.     Car run99 = { "run99",100,0 };  
  51.     run99.Accel();  
  52.     run99.Accel();  
  53.     run99.ShowCarState();  
  54.     cout << endl;  
  55.     run99.Break();  
  56.     run99.ShowCarState();  
  57.     cout << endl;  
  58.   
  59.     Car speed77 = { "speed77",100,0 };  
  60.     speed77.Accel();  
  61.     speed77.Break();  
  62.     speed77.ShowCarState();  
  63.   
  64.     return 0;  
  65. }  



[ 결과 ]



  • 4행~13행 : CAR_CONST 이름공간 안에 구조체 Car에서 사용하는 상수들을 모아놓았다.

  • 17행 : 상수 ID_LEN의 접근을 위해서 이름공간 CAR_CONST를 지정하고있다.

이렇듯 이름공간을 지정해서 코드를 작성했기 때문에, 이 문장만 봐도 이 상수가 어느 영역에서 선언되고 사용되는 상수인지 쉽게 알 수 있다. 그래서 기독성이 좋아졌다고 할 수 있다.


함수 외부로 빼기


함수가 포함되어 있는 C++의 구조체를 보는 순간 

다음의 정보들이 쉽게 눈에 들어와야 코드의 분석이 용이하다.


  • 선언되어 있는 변수 정보

  • 정의되어 있는 함수 정보


보통 프로그램을 분석할 때, 흐름 및 골격 위주로 분석하는 경우가 많다. 그리고 이러한 경우에는 함수의 기능만 파악을 하지, 함수의 세부구현까지 신경을 쓰지 않는다. 따라서 구조체를 보는 순간 정의되어 있는 함수의 종류와 기능이 한눈에 들어오게끔 코드를 작성하는 것이 좋다. 따라서 구조체 내에 정의되어 있는 함수의 수가 많거나 그 길이가 길다면, 다음과 같이 구조체 밖으로 함수를 빼낼 필요가 있다.


struct Car

{

    . . . . . .

    void ShowCarState( );

    void Accel( );

} ;


void Car :: ShowCarState( )

{

    . . . . . .

}


void Car :: Accel( )

{

    . . . . . . 

}


함수의 원형선언을 구조체 안에 두고, 함수의 정의를 구조체 밖으로 빼내는 것이다.

다만 빼낸 다음 해당 함수가 어디에 정의되어 있는지에 대한 정보만 추가해 주면 된다.


예제를 통해 살펴보자.


  • #include <iostream>  
    1. using namespace std;  
    2.   
    3. namespace CAR_CONST  
    4. {  
    5.     enum {  
    6.         ID_LEN = 20,  
    7.         MAX_SPD = 200,  
    8.         FUEL_STEP = 2,  
    9.         ACC_STEP = 10,  
    10.         BRK_STEP = 10  
    11.     };  
    12. }  
    13.   
    14. struct Car  
    15. {  
    16.     char gamerID[CAR_CONST::ID_LEN];  
    17.     int fuelGuage;  
    18.     int curSpeed;  
    19.   
    20.     void ShowCarState();  
    21.     void Accel();  
    22.     void Break();  
    23. };  
    24.   
    25. void Car::ShowCarState() {  
    26.     cout << "userID : " << gamerID << endl;  
    27.     cout << "guage  : " << fuelGuage << endl;  
    28.     cout << "speed  : " << curSpeed << endl;  
    29. }  
    30.   
    31. void Car::Accel() {  
    32.     if (fuelGuage <= 0)  
    33.         return;  
    34.     else  
    35.         fuelGuage -= CAR_CONST::FUEL_STEP;  
    36.   
    37.     if ((curSpeed + CAR_CONST::ACC_STEP) >= CAR_CONST::MAX_SPD) {  
    38.         curSpeed = CAR_CONST::MAX_SPD;  
    39.         return;  
    40.     }  
    41.   
    42.     curSpeed += CAR_CONST::ACC_STEP;  
    43. }  
    44.   
    45. void Car::Break() {  
    46.     if (curSpeed < CAR_CONST::BRK_STEP) {  
    47.         curSpeed = 0;  
    48.         return;  
    49.     }  
    50.   
    51.     curSpeed -= CAR_CONST::BRK_STEP;  
    52. }  
    53.   
    54. int main() {  
    55.     Car run99 = { "run99,100,0" };  
    56.     run99.Accel();  
    57.     run99.ShowCarState();  
    58.     cout << endl;  
    59.     run99.Break();  
    60.     run99.ShowCarState();  
    61.     return 0;  
    62. }  



    [ 결과 ]



    • 20~22행 : 구조체 안에 함수의 원형만 남으니, 함수의 종류가 한눈에 들어오고 적절한 주석을 통해 함수의 기능도 쉽게 판단이 가능하다.

    • 25,31,45행 : 원래 속하는 구조체의 이름을 명시하면서 구조체 밖으로 함수의 정의가 빠져나왔다.


    이로써 C++에서의 구조체에 대한 설명이 끝났다.

    그런데 C++에서의 구조체는 클래스의 일종으로 간주된다. 그래서 구조체 안에 함수를 정의할 수 있었던 것이다. 즉, 위에서 정의한 구조체를 가리켜 그냥 '클래스'라고 표현해도 틀리지 않는다.


    다음부터 작성되는 글에는 클래스와 객체에 대해 설명하겠다.

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

    C++ 기본(4) 객체지향 프로그래밍의 이해  (0) 2017.01.03
    C++ 기본(3) 클래스(Class)와 객체(Object)  (0) 2016.12.28
    8. C++ 기본(8)  (0) 2016.12.14
    7. C++ 기본(7)  (0) 2016.12.13
    6. C++ 기본(6)  (0) 2016.12.13

    + Recent posts