[ 문제 ]

#include <iostream>
using namespace std;
 
//`class Rect`를 구현하시오.
//
//- private: `int width, height`
//    - 생성자 `(width, height)`
//    - `int area() const`
//    - `void setWidth(int)`, `void setHeight(int)` : 0 미만이면 0 저장
 
 
class Rect {
    // 여기에 답안을 작성해주세요.
 
};
 
int main() {
    Rect r(3, 4);
    cout << r.area() << "\n"; // 12
    r.setWidth(-5); r.setHeight(2);
    cout << r.area() << "\n"; // 0
}

[ 개념 ]

  1. 접근 제어자 : C++에서 class를 만들고 public:이나 private:을 아무것도 적지 않으면, 기본적으로 맨 위에 있는 변수들은 자동으로 private이 됩니다.
    class Rect {
     // 키워드를 안 적어도 자동으로 private 구역이 됨!
     int width;
     int height;

public: // 아래에 public 함수들을 나열 Rect(int w, int h); int area() const; };


|    구분     |    접근 범위     |          특징          |
| :-------: | :----------: | :------------------: |
|  public   |  어디서든 접근 가능  |     외부 공개 API 역할     |
| protected | 클래스 + 자식 클래스 |    상속 관계에서만 접근 가능    |
|  private  |   클래스 내부만    | 외부/자식 모두 접근 불가 (기본값) |

2. `this` 포인터
 핵심 연산자
 1. 주소연산자 &
    변수 앞에 붙이면 "이 변수의 실제 메모리 주소가 어디야?"라고 묻는 것입니다.
 2. 역참조 연산자 *
    포인터 변수 앞에 붙이면 "네가 가리키고 있는 주소로 직접 찾아가서 값을 가져와(또는 바꿔)!"라는 의미입니다.

```cpp
int num = 10;     // 일반 변수 num에 10 저장
int* ptr = &num;  // ptr이라는 포인터 변수에 num의 '주소'를 저장

cout << ptr << "\n";  // 출력: 0x7ffe... (num의 메모리 주소값)
cout << *ptr << "\n"; // 출력: 10 (ptr이 가리키는 주소로 찾아가서 꺼낸 값)

① 멤버 변수와 매개변수의 이름이 같을 때 (이름 충돌 해결)

class Person {
private:
    string name; // 멤버 변수
public:
    void setName(string name) { // 매개변수 name
        // name = name; (X) -> 매개변수끼리 대입하는 의미 없는 코드가 됨
        this->name = name; // (O) -> 진짜 내 멤버 변수에 매개변수 값을 대입!
    }
};

② 멤버 함수에서 객체 자신을 다시 반환할 때 (연속 호출)

class Counter {
private:
    int count = 0;
public:
    Counter& add() {
        count++;
        return *this; // 내 객체 자체를 통째로 반환!
    }
};
 
// 사용 예시: 함수를 기차처럼 이어 붙여 쓸 수 있음
Counter c;
c.add().add().add();

③ 비교

구문의미실제 역할
ptr (일반 포인터)내가 임의로 지정한 메모리 주소임의의 대상 변수를 원격 제어할 때 사용
this (this 포인터)나 자신의 메모리 주소함수 내부에서 “지금 이 함수를 호출한 나 자신”을 의미
*this나 자신의 실제 알맹이(객체)함수가 종료되면서 자기 자신을 반환할 때 사용
  1. const 멤버 함수 멤버 변수 수정 불가능 : 함수 내부에서 멤버 변수의 값을 바꾸려고 하면 컴파일 에러가 발생 다른 일반 함수 호출 불가능 : const 함수 안에서는 값을 바꿀지도 모르는 일반 멤버 함수를 호출할 수 없고, 오직 다른 const 멤버 함수만 호출할 수 있습니다.
#include <iostream>
using namespace std;
 
class Person {
public:
    int age = 20;
 
    // 1. const 함수 (읽기 전용 🔎)
    void printAge() const {
        // age = 30; // ❌ 에러! const 함수 내에서는 값을 바꿀 수 없습니다.
        cout << age << "\n"; // ⭕ 값을 읽어서 출력하는 것만 가능!
    }
 
    // 2. 일반 함수 (수정 가능 ✏️)
    void birthday() {
        age++; // ⭕ 값을 마음대로 바꿀 수 있음!
    }
};
 
int main() {
    Person p;
    p.printAge(); // 20 출력
    p.birthday(); // 나이 1살 증가
    p.printAge(); // 21 출력
}

[ 풀이 ]

#include <iostream>
using namespace std;
 
//`class Rect`를 구현하시오.
//
//- private: `int width, height`
//    - 생성자 `(width, height)`
//    - `int area() const`
//    - `void setWidth(int)`, `void setHeight(int)` : 0 미만이면 0 저장
 
 
class Rect {
	int width;
	int height;
 
public:
	Rect(int width, int height)
	{
		this->width = width;
		this->height = height;
	}
	int area() const
	{
		return width * height;
	}
	void setWidth(int width)
	{
		if (width < 0)
		{
			this->width = 0;
		}
		else
		{
			this->width = width;
		}
	}
	void setHeight(int height)
	{
		if (height < 0)
		{
			this->height = 0;
		}
		else
		{
			this->height = height;
		}
	}
};
 
int main() {
	Rect r(3, 4);
	cout << r.area() << "\n"; // 12
	r.setWidth(-5); r.setHeight(2);
	cout << r.area() << "\n"; // 0
}

[ 해설 ]

#include <iostream> // 입출력을 위한 헤더 파일 포함
using namespace std; // std:: 네임스페이스 생략 설정
 
class Rect { // 사각형을 정의하는 Rect 클래스 시작
private: // 외부에서 직접 접근할 수 없는 보호 영역
    int width;  // 사각형의 가로 길이를 저장하는 멤버 변수
    int height; // 사각형의 세로 길이를 저장하는 멤버 변수
   
public: // 외부(main 함수 등)에서 자유롭게 접근할 수 있는 개방 영역
    // 생성자: 객체가 생성될 때 가로, 세로 값을 받아 초기화합니다.
    Rect(int width, int height) 
    {
        // 기존의 'this->width;'는 변수를 부르기만 하고 값을 넣지 않는 오류였습니다.
        // 대입 연산자(=)를 써서 매개변수 width를 진짜 멤버 변수(this->width)에 채워줍니다.
        this->width = width;   
        this->height = height; // 매개변수 height의 값을 멤버 변수 height에 대입합니다.
    }
 
    // 사각형의 넓이를 구해서 반환하는 멤버 함수
    // 뒤에 붙은 const는 이 함수 안에서 width나 height 값을 절대 변경하지 않겠다는 의미입니다.
    int area() const
    {
       return width * height; // 가로 * 세로 계산 결과를 반환
    }
 
    // 가로 길이를 외부에서 새로 수정하는 함수
    void setWidth(int width)
    {
        // 만약 받아온 가로 길이(매개변수 width)가 0보다 작다면(음수라면)
        if (width < 0) 
        {
            this->width = 0; // 사각형의 진짜 멤버 변수 가로 길이를 0으로 강제 세팅합니다.
        }
        // 그 외의 경우(0 이상인 정상적인 양수라면)
        else 
        {
            // 기존의 'width = width;'는 매개변수끼리 값을 주고받는 의미 없는 코드였습니다.
            // 명확하게 'this->'를 붙여서 진짜 멤버 변수에 매개변수 값을 대입해 줍니다.
            this->width = width; 
        }
    }
 
    // 세로 길이를 외부에서 새로 수정하는 함수
    void setHeight(int height)
    {
        // 입력받은 세로 길이가 음수인지 검사합니다.
        if (height < 0) 
        {
            this->height = 0; // 음수 유입 시 데이터 왜곡을 막기 위해 0으로 안전하게 저장합니다.
        }
        // 입력받은 세로 길이가 정상적인 양수라면
        else 
        {
            this->height = height; // 전달받은 값을 진짜 멤버 변수 height에 대입합니다.
        }
    }
}; // 클래스 정의 종료 (세미콜론 필수)
 
int main() { // 프로그램의 시작점인 main 함수
    Rect r(3, 4); // 가로 3, 세로 4를 가지는 사각형 객체 r 생성 (생성자 호출됨)
    cout << r.area() << "\n"; // area() 함수가 3 * 4를 계산하여 12 출력
    
    r.setWidth(-5); // 음수인 -5를 전달 -> setWidth 내부 조건문에 의해 가로(width)는 0이 됨
    r.setHeight(2); // 양수인 2를 전달 -> 세로(height)는 정상적으로 2가 됨
    
    cout << r.area() << "\n"; // 가로가 0이 되었으므로 0 * 2를 계산하여 0 출력
}