C++ 복습

열혈 C++ 복습 4

Captic 2019. 11. 22. 00:36

♨ 개인적 해석이 들어간 글임으로, 인지하지 못한 오류가 있을 수 있습니다 

교재 - <윤성우 열혈 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클래스 생성자를 정의할 수 있다

 

Initializer를 이용하여 Rectangle의 생성자에서 Point의 생성자를 2번 호출하고 있다

- 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형으로 선언되어야 한다 -> 오버로딩, 디폴트값 설정 불가

 

 

- 주로 생성자에서 할당한 리소스의 소멸에 사용

생성자에서 new? -> 소멸자에 delete

 

 

▣ 클래스와 배열 그리고 this 포인터

- 객체배열

 객체기반 배열의 선언 : 클래스명  배열이름[크기]   예) AAA arr[3];

  -> AAA 객체 3개를 담을 수 있는 배열 arr

 

객체배열을 선언하는 경우에도 생성자 호출, but 호출할 생성자 명시 불가(생성자에 인자 전달 불가)

-> 객체배열을 선언하기 위해서 " 생성자 (  ){  } " 와 같이 매개변수가 void인 생성자가 필요

또한 배열의 각 요소를 원하는 값으로 초기화 하려면, 개별적으로 접근하여 초기화 해야 한다

배열로 선언할 객체 ABC
실행부

 

- this 포인터의 이해

  this포인터는 그 값이 결정되어 있지 않은 포인터 -> 객체가 생성되면, 생성된 각 개체의 주소가 들어간다

  ∴ 객체를 생성한 후 부터 사용가능

 

 

- this 포인터의 활용

  매개변수가 멤버변수와 이름이 같을 때 멤버변수는 ' this->멤버변수 '와 같이 표현할 수 있다

앞서 나온 Point 객체 생성자 

  멤버변수인 (흰색)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;
}