메모장
열혈 C++ 복습 4 본문
♨ 개인적 해석이 들어간 글임으로, 인지하지 못한 오류가 있을 수 있습니다 ♨
교재 - <윤성우 열혈 C++ 프로그래밍>
▣ 정보은닉(Information Hiding)
- 정보은닉의 이해
변수에 대한 public / private 설정을 실수한다면, 잘못된 정보로 변수가 설정되거나
그 변수를 이용할 때( 예 - 함수의 매개변수로) 잘못된 수치가 반영될 수 있다
-> 제한된 방법(private 설정을 잘 해서)으로만 접근할 수 있게 하여 잘못된 값이 저장되지 않고
잘못 저장되었다고 하더라도 바로 발견되기 싶게 설정해야 한다
∴ 정보은닉 = 멤버변수를 private으로 선언하고, 해당 변수에 접근하는 함수를 별도로 정의해서,
안전한 형태로 멤버변수의 접근을 유도하는 것
-> 정보 은닉은 클래스 사용에 기본 소양? 정도 되겠다
※ 엑세스 함수(access function)
- private으로 선언된 멤버변수를 클래스 외부에서 접근할 수 있게 만든 함수
예)
- const 함수
const가 함수에 붙으면 해당 함수 내에서 멤버변수에 저장된 값을 변경하지 않겠다는 선언
+ const함수 내에서 const가 아닌 함수의 호출이 제한된다
(∵ const가 아닌 함수에 의해서 멤버변수 값이 변경될 수도 있기 때문)
예)
-> const 함수에서 const가 붙여지지 않은 함수를 호출할 수 없다
=> Shownum함수의 const를 제거하거나 Getnum함수에 const를 붙여야한다
+ const 레퍼런스 매개변수를 사용해도 const가 아닌 함수의 호출이 제한된다
예)
-> EasyClass의 객체를 매겨변수로 받아 EasyClass의 멤버변수를 구하는 함수를 구하려고 했지만
EasyClass 객체 매개변수가 const로 선언되었기 때문에 에러가 발생했다
=> Getnum함수에 const를 붙이거나 매개변수의 const를 제거해야 에러를 수정할 수 있다
▣ 캡슐화(Encapsulation)
- 캡슐화와 정보은닉의 구분
관련 있는 함수와 변수를 하나의 클래스로 합치는 것 = 캡슐화
예)
-> V1~V3를 Z1으로 캡슐화
+ 캡슐화를 통해 각 클래스의 멤버함수 실행 순서도 정할 수 있다 (31~33행)
V2 -> V3 -> V1 순으로 진행
구현하는 프로그램의 성격과 특성에 따라 캡슐화의 범위도 달라진다
-> 구체적인 정보를 바탕으로 여러 클래스에 있는 필요한 멤버변수, 함수를 종합해야한다
또한 캡슐화는 정보은닉이 기본적으로 포함된다 (하나로 합칠 때 멤버변수가 외부에 노출되지 않게 해야 한다)
▣ 생성자(Constructor)와 소멸자(Destructor)
- 생성자를 이용하면 객체 생성과 동시에 초기화를 할 수 있다
예)
-> 생성자는 객체 생성시 단! 한번! 호출된다
생성자 정의 X
예) SimpleClass sc; (전역/지역 및 매개변수의 형태)
SimpleClass * ptr = new SimpleClass; (동적 할당의 형태)
생성자 정의 O
예) SimpleClass sc(20);
SimpleClass * ptr = new SimpleClass(20);
- 생성자도 함수의 일종이기에, '오버로딩'이 가능하다 그리고 매개변수에 '디폴트 값' 설정도 가능하다
but! 중복해서 생성자를 만들면 에러
예)
▣ Member Initializer
A클래스 객체는 B클래스 객체 2개로 구성되어 있다
(예- Rectangle은 좌상단점(Point 객체)과 우하단점(Point 객체)로 구성)
이때 A클래스의 객체를 생성할 때 B객체의 생성자를 이용하여 A클래스 생성자를 정의할 수 있다
- Rectangle객체의 생성과정
1. 메모리 공간의 할당
2. 이니셜라이저를 이용한 멤버변수인 Point 객체의 초기화 (-> 이니셜라이저가 없으면 해당사항 X)
3. Rectangle 생성자의 Body 실행 (-> 생성자는 언제나 반드시 호출된다, 별도의 선언이 없으면 Default 생성자 호출)
- 이니셜라이저와 생성자 Body에서 멤버변수 초기화의 차이
이니셜라이저 사용 시
① 초기화 대상을 명확히 인식할 수 있다
② 성능의 약간의 이점
③ 선언과 동시에 초기화가 이루어지는 형태로 binary코드가 생성된다
-> const 멤버변수도 이니셜라이저로 초기화 가능하다
④ 멤버변수로 참조자(예- int& a)를 선언할 수 있게 한다
-> 참조자도 const 변수처럼 선언과 동시에 초기화 해야 한다
▣ 디폴트 생성자(Default Constructor)
- 객체가 되기 위해선 반드시 하나의 생성자가 호출되어야 한다
-> 생성자를 추가하지 않으면, C++ 컴파일러에 의해 디폴트 생성자가 삽입된다
- 디폴트 생성자는 인자를 받지도 않고, 내부적으로도(Body가) 비어있는 생성자
- new 연산자를 이용한 객체 생성에서도 생성자가 호출된다
※ C언어의 malloc 함수는 생성자 호출X --> 생성하려는 클래스의 크기 정보만 전달되기 때문
▣ 생성자 불일치
- 생성자는 반드시 한 번은 호출되어야 하기 때문에, 객체 생성 시 생성자에 맞추어 생성해야 한다
Example1 클래스의 생성자가 int형 인자를 받도록 되어있고,
별도의 매개변수가 void형인 생성자가 없기 때문에 Error
-> 에러를 없애려면 별도의, 매개변수가 void형인 생성자를
오버로딩해야한다
- Private 생성자
클래스 외부가 아닌 내부에서만 객체 생성을 하기 위해 생성자를 private으로 선언하기도 한다
▣ 소멸자의 이해와 활용
객체 생성시 必 실행 = 생성자
객체 소멸시 必 실행 = 소멸자
-> 소멸자 : 생성자 앞에 ' ~ '가 붙은 형태
반환형 선언 X, 실제로 반환 X
매개변수는 void형으로 선언되어야 한다 -> 오버로딩, 디폴트값 설정 불가
- 주로 생성자에서 할당한 리소스의 소멸에 사용
▣ 클래스와 배열 그리고 this 포인터
- 객체배열
객체기반 배열의 선언 : 클래스명 배열이름[크기] 예) AAA arr[3];
-> AAA 객체 3개를 담을 수 있는 배열 arr
객체배열을 선언하는 경우에도 생성자 호출, but 호출할 생성자 명시 불가(생성자에 인자 전달 불가)
-> 객체배열을 선언하기 위해서 " 생성자 ( ){ } " 와 같이 매개변수가 void인 생성자가 필요
또한 배열의 각 요소를 원하는 값으로 초기화 하려면, 개별적으로 접근하여 초기화 해야 한다
- this 포인터의 이해
this포인터는 그 값이 결정되어 있지 않은 포인터 -> 객체가 생성되면, 생성된 각 개체의 주소가 들어간다
∴ 객체를 생성한 후 부터 사용가능
- this 포인터의 활용
매개변수가 멤버변수와 이름이 같을 때 멤버변수는 ' this->멤버변수 '와 같이 표현할 수 있다
멤버변수인 (흰색)x는 생성된 Point 객체의 멤버변수인 x이기에 this를 사용하여 표현 가능
매개변수인 (회색)x는 객체 생성시 넣어주는, new Point(3, 4) 에서 3, 4를 의미 = this로 표현 불가
- Self-Reference 반환
Self Reference = 객체 자신을 참조할 수 있는 참조자 " *this " (객체 포인터를 이용한 역참조)
-> 함수 반환값이 *this일 경우 반환형을 " 클래스명& "로 표현
- 참조의 정보(참조값)에 대한 이해
문제풀기
▣ 4-1 정보은닉과 const
이전 '열혈복습 3'에서 나온 과일장수 코드 중 사과를 구매할 때 사용된 FruitBuyer 클래스의 멤버함수 BuyApples에 매개변수로 0보다 작은 수를 전달할 수 없다는 제약을 추가하되 일부 함수에 const를 선언하라
▣ 4-2 다양한 클래스의 정의
ㄱ. 주어진 Point 클래스를 기반으로 원을 의미하는 Circle 클래스를 정의하라
Circle 객체에는 1. 좌표상의 위치 정보(원의 중심좌표)와 반지름의 길이 정보를 저장 및 2. 출력이 가능해야 한다
class Point
{
private:
int xpos, ypos;
public:
void Init(int x, int y)
{
xpos = x;
ypos = y;
}
void ShowPointInfo() const
{
cout << "[" << xpos << ", " << ypos << "]" << endl;
}
};
ㄴ. Circle 클래스를 기반으로 Ring 클래스를 정의하라(바깥 원, 안쪽 원 - 도넛모양)
주의사항 - 바깥 원과 안쪽 원의 크기가 동일하면 오류
- 캡슐화를 염두하고 정의하라
ㄷ. 2 클래스(Circle, Ring)이 정의되었다면 아래의 main함수를 실행시켜라
int main(void)
{
Ring ring;
ring.Init(1, 1, 4, 2, 2, 9);
ring.ShowRingInfo();
return 0;
}
'C++ 복습' 카테고리의 다른 글
열혈 C++ 복습 3 (0) | 2019.11.19 |
---|---|
열혈 C++ 복습 2 (0) | 2019.11.17 |
열혈 C++ 복습 1 (0) | 2019.11.17 |
C++ 복습 1 (0) | 2019.08.04 |