2024. 4. 12. 14:18ㆍ[C++]/C++ 언어 기초
클래스와 구조체의 유일한 차이점
키워드 struct를 대신해 class를 사용하면, 구조체가 아닌 클래스가 된다.
class Car {
char gamerID[CAR_CONST::ID_LEN];
int fuelGauge;
int curSpeed;
void ShowCarState() { . . . . }
void Accel() { . . . . }
void Break() { . . . . }
- 키워드 struct가 아닌 class를 사용한 것이 코드상에서의 유일한 차이점이다.
- 그런데 이렇게 class로 키워드를 바꿔놓으면 변수(구조체 변수)를 선언하지 못한다.
Car run99 = {"run99", 100, 0}; // (X)
- 이유는 클래스 내에 선언된 함수에서가 아닌, 다른 영역에서 변수를 초기화하려 했기 때문이다.
- 클래스 내에 선언된 변수는 클래스 내에 선언된 함수에서만 접근 가능하다. (별도의 선언을 하지 않으면)
Car run99; // (O)
그럼 어떻게 초기화를 어떻게 하는가?
- 클래스는 정의를 하는 과정에서 각각의 변수 및 함수의 접근 허용범위를 별도로 선언해야 한다.
- 그럼 '접근제어 지시자'에 대해서 알아야 한다.
접근제어 지시자(접근제어 레이블)
C++의 접근제어 지시자는 다음과 같이 세 가지가 존재한다.
- public : 어디서든 접근허용
- protected : 상속관계에 놓여있을 때, 유도 클래스에서의 접근허용(상속)
- private : 클래스 내(클래스 내에 정의된 함수)에서만 접근허용
RacingCarClassBase.cpp
#include <iostream>
using namespace std;
namespace CAR_CONST {
enum {
ID_LEN = 20,
MAX_SPD = 200,
FUEL_STEP = 2,
ACC_STEP = 10,
BRK_STEP = 10
};
}
class Car
{
private:
char gamerID[CAR_CONST::ID_LEN]; // 소유자 ID
int fuelGauge; // 연료량
int curSpeed; // 현재속도
public:
void InitMembers(char * ID, int fuel);
void ShowCarState();
void Accel();
void Break();
};
void Car::InitMembers(char * ID, int fuel)
{
strcpy(gamerID, ID);
fuelGauge=fuel;
curSpeed = 0;
}
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.InitMembers("run99", 100);
run99.Accel();
run99.Accel();
run99.ShowCarState();
run99.Break();
run99.ShowCarState();
return 0;
}
소유자ID: run99
연료량: 96%
현재속도: 20km/s
소유자ID: run99
연료량: 96%
현재속도: 10km/s
- Car Class private 아래에 있는 변수들은 class 내부에서만 접근이 가능해졌고,
- public 아래에 있는 함수들은 어디서든지 접근이 가능해졌다.
- 이러한 접근제어 지시자를 지정하지 않으면 디폴트 값은 private이기에 모든 변수, 함수들이 class 내부에서만 접근이 가능해지는 것이다.
void Car::InitMembers(char * ID, int fuel)
{
strcpy(gamerID, ID);
fuelGauge=fuel;
curSpeed = 0;
}
- private선언으로 인해 class밖에서는 초기화를 할 수 없으므로 변수의 초기화를 목적으로 위의 InitMembers 함수를 class 내부에서 선언하고 class 외부에 정의했다.
- main함수에서는 이 함수의 호출을 통해 클래스 내부 선언된 변수를 초기화할 수 있게 된 것이다.
용어정리: 객체(Object), 멤버변수, 멤버함수
- RacingCarClassBase.cpp의 run99는 '변수'가 아닌 '객체'라고 표현을 바꿔야 한다.
- 구조체 변수, 클래스 변수라는 표현은 이제 어울리지 않는다. 구조체와 클래스는 변수의 성격만 지니는 것이 아니기 때문이다.
- 변수라는 표현을 대신해 '객체(Object)'라는 표현을 사용한다.
- 클래스를 구성하는(클래스 내에 선언된) 변수를 '멤버변수'라 한다.
char gamerID[CAR_CONST::ID_LEN];
int fuelGauge;
int curSpeed;
클래스를 구성하는(클래스 내에 정의된) 함수를 '멤버함수'라 한다.
void InitMembers(char * ID, int fuel);
void ShowCarState();
void Accel();
void Break();
C++에서의 파일분할
C++에서의 파일분할에 대해 이야기해 보자. 클래스 Car을 대상으로 파일을 나눌 때에는 보통 다음과 같이 파일을 구분한다.
- Car.h : 클래스의 선언을 담는다.
- Car.cpp : 클래스의 정의(멤버함수의 정의)를 담는다.
클래스의 선언
class Car
{
private:
char gamerID[CAR_CONST::ID_LEN]; // 소유자 ID
int fuelGauge; // 연료량
int curSpeed; // 현재속도
public:
void InitMembers(char * ID, int fuel);
void ShowCarState();
void Accel();
void Break();
};
- Car 클래스와 관련된 문장의 오류를 잡아내는데 필요한 최소한의 정보로써, 클래스의 외형적인 틀을 보여준다.
- 이를 '클래스의 선언(declaration)'이라 한다.
클래스의 정의
void Car::InitMembers(char *ID, int fuel) { . . . . }
void Car::ShowCarState() { . . . . }
void Car::Accel() { . . . . }
void Car::Break() { . . . . }
- '클래스의 정의(definition)'에 해당하는 다음 함수의 정의는 다른 문장의 컴파일에 필요한 정보를 가지고 있지 않다.
- 따라서 함수의 정의는 컴파일 된 이후에, 링커에 의해 하나의 실행파일로 묶이기만 하면 된다.
결론은, '클래스의 선언'은 헤더파일에, '클래스의 정의'는 소스파일에 저장한다.
파일 분할 예시
Car.h
#ifndef __CAR_H__
#define __CAR_H__
namespace CAR_CONST {
enum {
ID_LEN = 20,
MAX_SPD = 200,
FUEL_STEP = 2,
ACC_STEP = 10,
BRK_STEP = 10
};
}
class Car
{
private:
char gamerID[CAR_CONST::ID_LEN]; // 소유자 ID
int fuelGauge; // 연료량
int curSpeed; // 현재속도
public:
void InitMembers(char * ID, int fuel);
void ShowCarState();
void Accel();
void Break();
};
#endif __CAR_H__
Car.cpp
#include <iostream>
#include <cstring>
#include "Car.h"
using namespace std;
void Car::InitMembers(char * ID, int fuel)
{
strcpy(gamerID, ID);
fuelGauge=fuel;
curSpeed = 0;
}
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;
}
RacingMain.cpp
#include "Car.h"
int main(void) {
Car run99;
run99.InitMembers("run99", 100);
run99.Accel();
run99.Accel();
run99.ShowCarState();
run99.Break();
run99.ShowCarState();
return 0;
}
소유자ID: run99
연료량: 96%
현재속도: 20km/s
소유자ID: run99
연료량: 96%
현재속도: 10km/s
인라인 함수는 헤더파일에 함께 넣어야 해요.
- 인라인 함수는 컴파일을 할 때, 함수의 호출부분을 몸체로 바꿔버린다.
- 따라서 선언과 동시에 정의가 필요하다. 이는 따로 분리를 하면 안된다는 말이다.
- 결론은 인라인 함수 선언과 정의를 한꺼번에 헤더파일(.h) 안에 통째로 넣어야 한다.
CarInline.h
#ifndef __CAR_H__
#define __CAR_H__
#include <iostream>
using namespace std;
namespace CAR_CONST {
enum {
ID_LEN = 20,
MAX_SPD = 200,
FUEL_STEP = 2,
ACC_STEP = 10,
BRK_STEP = 10
};
}
class Car
{
private:
char gamerID[CAR_CONST::ID_LEN]; // 소유자 ID
int fuelGauge; // 연료량
int curSpeed; // 현재속도
public:
void InitMembers(char * ID, int fuel);
void ShowCarState();
void Accel();
void Break();
};
inline void Car::ShowCarState()
{
cout<<"소유자ID: "<<gamerID<<endl;
cout<<"연료량: "<<fuelGauge<<"%"<<endl;
cout<<"현재속도: "<<curSpeed<<"km/s"<<endl<<endl;
}
inline void Car::Break()
{
if(curSpeed<CAR_CONST::BRK_STEP)
{
curSpeed=0;
return;
}
curSpeed-=CAR_CONST::BRK_STEP;
}
#endif __CAR_H__
CarInline.cpp
#include <cstring>
#include "CarInline.h"
using namespace std;
void Car::InitMembers(char * ID, int fuel)
{
strcpy(gamerID, ID);
fuelGauge=fuel;
curSpeed = 0;
}
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;
}
RacingInlineMain.cpp
#include "CarInline.h"
int main(void) {
Car run99;
run99.InitMembers("run99", 100);
run99.Accel();
run99.Accel();
run99.ShowCarState();
run99.Break();
run99.ShowCarState();
return 0;
}
실습 문제
문제 1
계산기 기능의 Calculator 클래스를 정의해보자. 기본적으로 지니는 기능은 덧셈, 뺄셈, 곱셈 그리고 나눗셈이며, 연산을 할 때마다 어떠한 연산을 몇 번 수행했는지 기록되어야 한다. 아래의 main 함수와 실행의 예에 부함하는 Calculator 클래스를 정의하면 된다. 단, 멤버변수는 private으로, 멤버함수는 public으로 선언하자.
int main(void)
{
Calculator cal;
cal.Init();
cout << "3.2+2.4= "<< cal.Add(3.2, 2.4) << endl;
cout << "3.5/1.7="<< cal.Div(3.5, 1.7) << endl;
cout << "2.2-1.5="<< cal.Min(2.2, 1.5) << endl;
cout << "4.9/1.2="<< cal.Div(4.9, 1.2) << endl;
cal.ShowOpCount();
return 0;
}
내 풀이
#include "stdafx.h"
#include <iostream>
#include <cstring>
using namespace System;
using namespace std;
class Calculator{
private:
int Add_num;
int Min_num;
int Multi_num;
int Div_num;
public:
void Init();
double Add(double num1, double num2);
double Min(double num1, double num2);
double Multi(double num1, double num2);
double Div(double num1, double num2);
void ShowOpCount();
};
void Calculator::Init()
{
Add_num=0;
Min_num=0;
Multi_num=0;
Div_num=0;
}
double Calculator :: Add(double num1, double num2){
Add_num++;
return num1 + num2;
}
double Calculator::Min(double num1, double num2){
Min_num++;
return num1 - num2;
}
double Calculator::Multi(double num1, double num2){
Multi_num++;
return num1 * num2;
}
double Calculator::Div(double num1, double num2){
Div_num++;
return num1 / num2;
}
void Calculator::ShowOpCount(){
cout<< "덧셈: " << Add_num << " 뺄셈: "<<Min_num << " 곱셈: " << Multi_num<< " 나눗셈: " <<Div_num << endl;
}
int main (void)
{
Calculator cal;
cal.Init();
cout << "3.2 + 2.4 = "<< cal.Add(3.2, 2.4) << endl;
cout << "3.5 / 1.7 = "<< cal.Div(3.5, 1.7) << endl;
cout << "2.2 - 1.5 = "<< cal.Min(2.2, 1.5) << endl;
cout << "4.9 / 1.2 = "<< cal.Div(4.9, 1.2) << endl;
cal.ShowOpCount();
return 0;
}
문제 2
문자열 정보를 내부에 저장하는 printer라는 이름의 클래스를 디자인하자.
이 클래스의 두 가지 기능은 다음과 같다
1.문자열 저장
2.문자열 출력
아래의 main 함수와 실행의 예에 부합하는 Printer 클래스를 정의하되,이번에도 역시 멤버변수는 private, 멤버함수는 public으로 선언하자
int main(void)
{
Printer pnt;
pnt.SetString("Hello world!");
pnt.ShowString();
pnt.SetString("I love C++");
pnt.ShowString();
return 0;
}
내 풀이
#include "stdafx.h"
#include <iostream>
#include <cstring>
using namespace System;
using namespace std;
class Printer{
private:
char str1[30];
public:
void SetString(char* str);
void ShowString();
};
void Printer :: SetString(char* str){
strcpy(str1, str);
}
void Printer::ShowString(){
cout<<str1<<endl;
}
int main (void)
{
Printer pnt;
pnt.SetString("Hello world!");
pnt.ShowString();
pnt.SetString("I love C++");
pnt.ShowString();
return 0;
}
'[C++] > C++ 언어 기초' 카테고리의 다른 글
16. [C++] 생성자(Constructor)와 소멸자(Destructor) (0) | 2024.04.12 |
---|---|
15. [C++] 객체지향 프로그래밍의 이해, 정보은닉, 캡슐화 (0) | 2024.04.12 |
13. [C++] C++에서의 구조체 (0) | 2024.04.12 |
12. [C++] C++에서 C언어의 표준함수 호출하기 (0) | 2024.04.11 |
11. [C++] malloc & free를 대신하는 new & delete (0) | 2024.04.11 |