[Cpp]클래스(1)
📚클래스
클래스는 멤버들의 집합으로 구성된 데이터 형식입니다. 클래스의 크기는 멤버에 따라 변합니다. 구조체와 동일하게 8byte만 사용됩니다. 하지만 멤버함수는 클래스의 크기에 영향을 주지 않습니다. 멤버함수는 시그니쳐 정보로 개별 처리되어 다른 함수들과 함께 함수 테이블이라는 특정 공간에 일괄 저장됩니다.
📄접근제한자
클래스 안에서 사용되는 데이터는 접근제한자(Access Modifiers)라는 것을 사용하여 3가지 방법으로 숨길 수 있습니다.
- public: 클래스 내/외부에서 모두 사용 가능. 멤버함수, 객체로 만든 후 객체를 통해서도 접근 가능.
- protected: 자신과 자신을 기반으로 하는 파생클래스에서 사용 가능. 자신의 멤버함수, 파생된 멤버함수에서 접근 가능.
- private: 클래스 내부에서만 사용 가능. 기본이 되는 값으로 접근제한자를 생략하면 private이 됨. 멤버함수에서만 접근 가능.
1
2
3
4
5
6
7
8
9
10
11
12
class Animal
{
private:
int mAge;
public:
unsigned int mWeight;
int mColor;
public:
void Walk();
};
📄이름 규칙
- 클래스 이름: 파스칼 표기법(Animal, Cat, Dog, Player 등등)
- 멤버 변수: 소문자 m을 붙여 멤버를 명시하고 파스칼 표기법 적용(mAge, mColor 등등)
- 멤버함수: 파스칼 표기법(IsDead(), Fire() 등등)
📄클래스와 구조체
구조체는 모든 멤버가 public인 클래스의 일부분이라고 볼 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// C++에서 구조체에 멤버함수를 작성할 수 있음
// C에서는 불가능
struct Coordination
{
int x;
int y;
void Print();
};
class Coordination
{
public:
int x;
int y;
void Print();
};
📄멤버함수 구현
멤버함수의 몸체는 클래스 선언 내부에 간단하게 만들 수 있습니다.
1
2
3
4
5
6
7
8
class Dog
{
public:
void Bark()
{
// 함수 몸체
}
};
하지만 함수의 몸체가 길어지면 클래스 선언이 보기 불편해집니다. 따라서 일반 함수들이 선언과 정의를 분리하는 형태로 멤버함수도 정의를 분리할 수 있습니다.
1
2
3
4
5
6
반환형 클래스이름::함수이름(매개변수 목록)
{
...
return 반환값;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Dog
{
private:
int mAge;
public:
int GetAge();
};
// 범위해결연산자(::): '클래스이름::함수이름' 형태로 멤버함수의 소속 클래스를 명시
// 접근제한자 생략: 함수 선언에 이미 존재하므로 정의에는 생략
int Dog::GetAge()
{
retrun mAge;
}
💡멤버함수 선언 순서
일반함수는 선언 순서가 중요하지만 클래스에서 멤버함수들의 순서에는 제약이 없습니다. 클래스의 선언은 모든 내용이 마무리되는 ;을 만나는 순간 이뤄지기 때문에 멤버함수들은 서로 존재를 알고 있기 때문입니다.
📄this
클래스는 청사진 용도로 타입을 만드는 것이고, 실제 값은 메모리에 이름을 붙여서 할당한 인스턴스가 들고 있습니다.
암시적 오브젝트를 명시적으로 사용하기 위해 this라는 키워드를 사용할 수 있습니다. this는 멤버함수를 호출한 객체의 포인터를 나타냅니다.
1
2
3
4
5
6
7
8
9
10
11
// 암시적 오브젝트 표현
int Student::GetNumber()
{
return mNumber;
}
// this 키워드를 사용한 명시적 표현
int Student::GetNumber()
{
return this->mNumber;
}
this는 객체 자신을 반환할 때 유용하게 사용됩니다. 모든 함수는 this라는 포인터가 존재합니다.
📄클래스 객체의 사용법
이름을 부여하고 선언하면 메모리에 할당되는데 이것을 인스턴스화라고 부르고 생성된 객체를 인스턴스라고 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
class MyClass
{
private:
int mNumber;
public:
int GetNumber()
{
return mNumber;
}
};
// MyClass는 클래스이고 c는 MyClass 클래스의 인스턴스입니다.
MyClass a;
// 클래스 멤버에 접근하기 위해 구조체와 만찬가지로 점 연산자를 사용합니다.
a.mNumber = 1;
// 동적 할당도 가능합니다. 포인터는 화살표 연산자를 사용합니다.
MyClass* b = new MyClass;
b->GetNumber();
📄캡슐화
사용자에게 노출된 기능을 인터페이스라고 부르고 기능 내부에서 복잡한 기술로 작동시키는 것을 구현이라고 합니다.
객체를 특정짓는 상태와 행동을 하나로 묶어서 관리하는 것을 캡슐화라고 합니다. 캡슐형 알약을 생각해보면 알약 내부에 무엇이 들어 있는지 모르고 간단히 복용할 수 있는 것 처럼 외부에서 객체를 볼 때 하나의 캡슐만 파악하면 되고 내부의 상태와 행동은 몰라도 되게 해주기 때문에 명료한 프로그램 작성을 도와줍니다.
📄정보 은닉
캡슐화를 사용하여 외부에 불필요하거나 보안이 필요한 정보를 숨길 수 있는 것을 정보 은닉이라고 합니다. 데이터의 정확성과 일관성을 유직하는 것을 무결성이라고 합니다.
📄상수 멤버함수
멤버함수도 상수 함수로 만들 수 있습니다. 멤버함수 선언 뒤에 const를 붙이면 멤버함수는 상수 함수가 되고 함수 내부에서 클래스의 멤버의 어떤 값도 변경하지 않는다는 의미가 됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
반환형 함수이름(매개변수) const;
class Cat
{
private:
int mAge;
public:
int GetAge() const
{
mAge = 1; // 컴파일 오류
return mAge;
}
};
const 멤버함수에서 클래스의 다른 멤버 변수 값을 변경하면 컴파일 오류가 발생합니다. 이런 특성 때문에 가능하다면 const 멤버함수를 사용해서 클래스 설계자의 의도를 명확하게 하고 프로그래머의 실수를 방지해야 합니다.
const 멤버함수는 Getter/Setter라는 특수한 형태의 멤버함수 사용에 유용합니다.
- 속성
한 객체에 대해 어떤 객체를 주고 받을 수 있는 행위를 나타냅니다. 또한 속성은 상태가 아닌 행동에 중점을 두고 있습니다. 멤버 변수에 접근하는 것을 막고 멤버함수로 접근하게 하려는 것이 목적입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Calendar
{
private:
int mMonth;
public:
void SetMonth(std::string month)
{
// month에 값 지정
}
std::string GetMonth() const
{
// month에 따라 문자열 반환
}
};
내부에서 연산을 위해 월을 정수로 관리하지만 실제 사용자가 달력을 볼 때는 문자열을 보게 되어야합니다. 이렇게 내부에서 사용하는 데이터는 private으로 접근을 막고, public 멤버함수로 Getter와 Setter를 만들어서 설계하는 사람의 실수를 줄이고 사용하는 사람이 읽기 쉽게 만들어야합니다. 주로 Getter에서 const 멤버함수를 사용합니다.
- const 키워드 활용
- const 변수: 값을 변경할 수 없는 상수 변수로 리터럴로 사용할 때 주로 사용됩니다. const int NAME_LEN = 10;
- const 매개변수: 함수 내부에서 매개변수의 값을 변경하지 않는다는 의미입니다. Call By Reference와 같이 매개변수가 변경될 가능성이 있는 곳에 사용하면 됩니다. void PrintInfo(const Stack& stack);
- const 반환형 함수: 매개변수와 마찬가지로 반환형에 참조형이 사용될 때 해당 반환값을 변경할 수 없다는 사실을 명확하게 표현할 때 사용합니다. const Stack& GetStack();
- const 멤버함수: 멤버함수 내부에서 클래스의 멤버변수 값을 수정하지 않는다는 의미입니다. int GetNumber() const;
- const 포인터
- const int* p1; - p1은 상수 정수를 가리키는 포인터입니다. p1이 가리키는 값을 수정할 수 없다는 의미입니다. *p1 = 1; // error
- int* const p2; - p2는 정수를 가리키는 상수 포인터입니다. p2가 가리키는 값은 변경 가능하지만 포인터 p2는 다른 것을 가리키도록 변경할 수 없습니다. p2 = &a; // error
- const int* const p3; - p1, p2 특성을 모두 가져서 p3가 가리키는 값을 변경할 수 없고, p3도 다른 것을 가리키도록 변경할 수 없습니다. *p3 = 10; // error, p3 = &a; // error
Leave a comment