본문 바로가기
C++

C++에서의 구조체

by KWONE 2024. 7. 21.

C와 달리 C++에서는 구조체에 함수를 포함시킬 수 있다. 이는 데이터만을 포함하는 일반적인 구조체와 달리

데이터의 처리 기능을 포함하기 때문에 클래스로 칭한다. (클래스=데이터+처리기능)

1. C++에서는 별도의 typedef선언 없이 구조체 변수를 선언할 수 있다.

2. 구조체 안에 함수를 삽입할 수 있다.

구조체 안의 함수임에도 불구하고 전역함수의 형태를 띠는데, 구조체 안의 함수들이 구조체에 종속적임을 잊어선 안된다.

따라서 다른 영역에서 이 함수를 호출하면 안된다.

struct Car
{
	char gamerID[ID_LEN];	// 소유자ID
	int fuelGauge;		// 연료량
	int curSpeed;		// 현재속도

	void ShowCarState()
	{
		cout<<"소유자ID: "<<gamerID<<endl;
		cout<<"연료량: "<<fuelGauge<<"%"<<endl;
		cout<<"현재속도: "<<curSpeed<<"km/s"<<endl<<endl;
	}
	void Accel()
	{
		if(fuelGauge<=0)
			return;
		else
			fuelGauge-=FUEL_STEP;

		if(curSpeed+ACC_STEP>=MAX_SPD)
		{
			curSpeed=MAX_SPD;
			return;
		}
	
		curSpeed+=ACC_STEP;
	}
	void Break()
	{
		if(curSpeed<BRK_STEP)
		{
			curSpeed=0;
			return;
		}

		curSpeed-=BRK_STEP;
	}
};

구조체안에 함수를 삽입하기 전에는 함수 정의에 있어서 우선 매개변수로 참조자 car을 전달받아야한다.

void ShowCarState(const Car &car)
	{
		cout<<"소유자ID: "<<car.gamerID<<endl;
		cout<<"연료량: "<<car.fuelGauge<<"%"<<endl;
		cout<<"현재속도: "<<car.curSpeed<<"km/s"<<endl<<endl;
	}

그러나 위의 코드에서는 구조체안에 함수를 삽입하여서 아래와 같은 차이를 보인다.

void ShowCarState()
	{
		cout<<"소유자ID: "<<gamerID<<endl;
		cout<<"연료량: "<<fuelGauge<<"%"<<endl;
		cout<<"현재속도: "<<curSpeed<<"km/s"<<endl<<endl;
	}

매개변수 명시가 필요없어지고, 구조체 멤버car을 참조할 필요가 없어졌다.

이렇게 연산의 대상에 대한 정보가 불필요한 이유는,

함수가 구조체 내에 삽입되면서 구조체 내에 선언된 변수에 직접접근이 가능해졌기 때문이다.

따라서 다음과 같이 구조체 변수를 선언하면 각각의 구조체 변수가 생성된다.

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

각각의 구조체 변수가 생성될때 함수는 하나의 함수를 공유한다.

다만 논리적으로 각각의 구조체 변수가 별도로 지니는 것과 같은 효과 및 결과를 보인다.

#include <iostream>
using namespace std;

#define ID_LEN		20
#define MAX_SPD		200
#define FUEL_STEP	2
#define ACC_STEP	10
#define BRK_STEP	10

struct Car
{
	char gamerID[ID_LEN];	// 소유자ID
	int fuelGauge;			// 연료량
	int curSpeed;			// 현재속도

	void ShowCarState()
	{
		cout<<"소유자ID: "<<gamerID<<endl;
		cout<<"연료량: "<<fuelGauge<<"%"<<endl;
		cout<<"현재속도: "<<curSpeed<<"km/s"<<endl<<endl;
	}
	void Accel()
	{
		if(fuelGauge<=0)
			return;
		else
			fuelGauge-=FUEL_STEP;

		if(curSpeed+ACC_STEP>=MAX_SPD)
		{
			curSpeed=MAX_SPD;
			return;
		}
	
		curSpeed+=ACC_STEP;
	}
	void Break()
	{
		if(curSpeed<BRK_STEP)
		{
			curSpeed=0;
			return;
		}

		curSpeed-=BRK_STEP;
	}
};


int main(void)
{
	Car run99={"run99", 100, 0};
	run99.Accel();
	run99.Accel();
	run99.ShowCarState();
	run99.Break();
	run99.ShowCarState();

	Car sped77={"sped77", 100, 0};
	sped77.Accel();
	sped77.Break();
	sped77.ShowCarState();
	return 0;
}
int main(void)
{
	Car run99={"run99", 100, 0};
	run99.Accel();
	run99.Accel();
	run99.ShowCarState();
	run99.Break();
	run99.ShowCarState();

	Car sped77={"sped77", 100, 0};
	sped77.Accel();
	sped77.Break();
	sped77.ShowCarState();
	return 0;
}

메인함수를 살펴보면 각각 생성된 구조체 변수 run99에 존재하는것 처럼 보이는 Accel함수를 호출하고 있다.

(사실은 run99 변수와 sped77변수 모두 하나의 구조체 안의 함수를 공유하는것이다. 하지만 각각 가지는것으로 생각한다.)

3.매크로 사용대신 구조체 안에 enum 상수 선언 

#define ID_LEN		20
#define MAX_SPD		200
#define FUEL_STEP	2
#define ACC_STEP	10
#define BRK_STEP	10

이 매크로 상수들은 모두 구조체 Car에게만 의미있는 상수들이기 때문에 구조체 내에 포함시킬 수 있다.

따라서 이러한 경우 열거형 enum을 사용해서 구조체 내에서만 유효한 상수로 정의할 수 있다.

struct Car
{
	enum
	{
		ID_LEN = 20,
		MAX_SPD = 200,
		FUEL_STEP = 2,
		ACC_STEP = 10,
		BRK_STEP = 10
	};

	char gamerID[ID_LEN];	// 소유자ID
	int fuelGauge;			// 연료량
	int curSpeed;			// 현재속도

	void ShowCarState() {}
	void Accel() {}
	void Break() {}
};

매크로 상수들을 구조체 내부에 삽입하는 것이 걱정되면 이름공간을 사용해서 상수가 사용되는 공간을 명시할 수도 있다.

#include <iostream>
using namespace std;

namespace CAR_CONST
{
	enum
	{
		ID_LEN		=20,
		MAX_SPD		=200,
		FUEL_STEP	=2,
		ACC_STEP	=10,
		BRK_STEP	=10
	};
}

struct Car
{
	char gamerID[CAR_CONST::ID_LEN];	
	int fuelGauge;		
	int curSpeed;		

	void ShowCarState()
	{
		cout<<"소유자ID: "<<gamerID<<endl;
		cout<<"연료량: "<<fuelGauge<<"%"<<endl;
		cout<<"현재속도: "<<curSpeed<<"km/s"<<endl<<endl;
	}
	void Accel()
	{
		if(fuelGauge<=0)
			return;
		else
			fuelGauge-=CAR_CONST::FUEL_STEP;

		if((curSpeed+CAR_CONST::ACC_STEP)>=CAR_CONST::MAX_SPD)
		{
			curSpeed=CAR_CONST::MAX_SPD;
			return;
		}
	
		curSpeed+=CAR_CONST::ACC_STEP;
	}
	void Break()
	{
		if(curSpeed<CAR_CONST::BRK_STEP)
		{
			curSpeed=0;
			return;
		}

		curSpeed-=CAR_CONST::BRK_STEP;
	}
};

int main(void)
{
	Car run99={"run99", 100, 0};
	run99.Accel();
	run99.Accel();
	run99.ShowCarState();
	run99.Break();
	run99.ShowCarState();

	Car sped77={"sped77", 100, 0};
	sped77.Accel();
	sped77.Break();
	sped77.ShowCarState();
	return 0;
}
namespace CAR_CONST
{
	enum
	{
		ID_LEN		=20,
		MAX_SPD		=200,
		FUEL_STEP	=2,
		ACC_STEP	=10,
		BRK_STEP	=10
	};
}

이렇게 CAR_CONST 이름공간 안에 구조체 Car에서 사용하는 상수들을 모아두었다.

struct Car
{
	char gamerID[CAR_CONST::ID_LEN];	
	int fuelGauge;		
	int curSpeed;		

	void ShowCarState()
	{
		cout<<"소유자ID: "<<gamerID<<endl;
		cout<<"연료량: "<<fuelGauge<<"%"<<endl;
		cout<<"현재속도: "<<curSpeed<<"km/s"<<endl<<endl;
	}
	void Accel()
	{
		if(fuelGauge<=0)
			return;
		else
			fuelGauge-=CAR_CONST::FUEL_STEP;

		if((curSpeed+CAR_CONST::ACC_STEP)>=CAR_CONST::MAX_SPD)
		{
			curSpeed=CAR_CONST::MAX_SPD;
			return;
		}
	
		curSpeed+=CAR_CONST::ACC_STEP;
	}
	void Break()
	{
		if(curSpeed<CAR_CONST::BRK_STEP)
		{
			curSpeed=0;
			return;
		}

		curSpeed-=CAR_CONST::BRK_STEP;
	}
};

상수의 접근을 위해서는 이름공간 CAR_CONST를 지정하고 사용하면 된다. 

ex: (CAR_CONST::ID_LEN),(CAR_CONST::FUEL_STEP)

4.함수의 원형선언만 구조체 안에 두고, 함수의 정의는 구조체 밖으로 뺄 수 있다.

struct Car
{
	char gamerID[CAR_CONST::ID_LEN];	
	int fuelGauge;		
	int curSpeed;		

	void ShowCarState();
	void Accel();
	void Break();
};
void Car::ShowCarState()
{
	cout<<"소유자ID: "<<gamerID<<endl;
	cout<<"연료량: "<<fuelGauge<<"%"<<endl;
	cout<<"현재속도: "<<curSpeed<<"km/s"<<endl<<endl;
}
void Car::Accel()
{
	if(fuelGauge<=0)
		return;
	else
		fuelGauge-=CAR_CONST::FUEL_STEP;

	if((curSpeed+CAR_CONST::ACC_STEP)>=CAR_CONST::MAX_SPD)
	{
		curSpeed=CAR_CONST::MAX_SPD;
		return;
	}

	curSpeed+=CAR_CONST::ACC_STEP;
}
void Car::Break()
{
	if(curSpeed<CAR_CONST::BRK_STEP)
	{
		curSpeed=0;
		return;
	}

	curSpeed-=CAR_CONST::BRK_STEP;
}
int main(void)
{
	Car run99={"run99", 100, 0};
	run99.Accel();
	run99.ShowCarState();
	run99.Break();
	run99.ShowCarState();
	return 0;
}

사실 구조체 안에 함수가 정의되어 있으면 "함수를 인라인으로 처리하라"는 의미가 내포되어있기에  나타내는바가 다르다.

하지만 inline키워드를 사용하여 명시적으로 지시하면 같게 사용할 수 있다.

inline void ShowCarState(){};
inline void Accel(){};
inline void Break(){};

 

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

정보은닉 (Information Hiding)  (0) 2024.07.26
클래스 (class)  (1) 2024.07.22
이름 공간 (namespace)  (2) 2024.07.17
scanf를 대신하는 데이터의 입력  (0) 2024.07.15
HELLO WORLD  (0) 2024.07.15