[열혈 c++ 프로그래밍] ch4

hyng·2023년 3월 12일
0

열혈 c++ 프로그래밍을 보고 요약정리합니다.

4-1 정보은닉의 이해

  • 멤버변수를 private으로 선언하고, 해당 변수에 접근하는 함수를 별도로 정의해서, 안전한 형태로 멤버 변수의 접근을 유도하는 것이 바로 ‘정보은닉’이며, 이는 좋은 클래스가 되기 위한 기본조건이 된다.
  • const 함수
    • 멤버변수에 저장된 값을 변경하지 않겠다. → 변경한다면 컴파일 에러 발생

    • const 함수 내에서 const 가 아닌 함수의 호출이 제한된다.

      굳이 사용할까 싶었음. 멤버변수에 변경을 막는다면 변수에 직접 const 를 붙이는게 더 직관적일듯,

4-2 캡슐화

  • 관련성이 높고, 의존도가 높은 데이터들을 하나로 묶는 것

4-3 생성자와 소멸자

class SimpleClass
{
private:
    int num1;
    int num2;
public:
    SimpleClass() {
        num1 = 0;
        num2 = 0;
    }
    SimpleClass(int n) {
        num1 = n;
        num2 = 0;
    }
    SimpleClass(int n1, int n2)
    {
        num1 = n1;
        num2 = n2;
    }
};
  • 생성자도 함수의 일종이니 오버로딩이 가능하다.
  • 생성자도 함수의 일종이니 매개변수에 디폴트 값을 설정할 수 있다.
  • 멤버 이니셜라이저를 이용한 멤버 초기화
    Rectangle::Rectangle(const int &x1, const int &y1, const int &x2, const int &y2) :upLefet(x1, y1), lowRight(x2, y2) 
    {
    		//empty
    }
    • 객체 upLeft의 생성과정에서 x1과 y1을 인자로 전달받는 생성자를 호출하라.
    • 객체 lowRight의 생성과정에서 x2와 y2을 인자로 전달받는 생성자를 호출하라.
    • 객체 생성과정:
      • 메모리 공간의 할당
      • 이니셜라이저를 이용한 멤버변수의 초기화
      • 생성자의 몸체부분 실행
    • 변수도 멤버 이니셜라이저를 통해 초기화 가능하다.
      • 이니셜라이저를 이용하면 선언과 동시에 초기화가 이뤄지는 형태로 바이너리 코드가 생성되기 때문에 const 멤버 변수도 이니셜라이저를 이용하면 초기화가 가능하다.

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

  • 객체 배열

    • SoSimple arr[10]

      class Person {
      public:
          Person() {
              cout << "생성자 호출됨" << endl;
          }
      };
      int main() {
          Person arr[3];
      }

    • SoSimple * ptrArr = new SoSimple[10]

        class Person {
        public:
            Person() {
                cout << "생성자 호출됨" << endl;
            }
        };
        int main() {
            Person *arr = new Person[3];
      			```

  • 객체 포인터 배열
    • 객체 배열 - 객체로 이뤄진 배열
    • 객체 포인터 배열 - 객체의 주소 값 저장이 가능한 포인터 배열
  • self-reference 반환
class SelfRef
{
	private:
		int num;
	public:
		SelfRef& Adder(int n)
		{
			 num += n;
			 return *this; //이 문장을 실행하는 객체 자신의 포인터가 아닌, 객체 자신을 반환하겠다는 의미
		}
};

OOP 단계별 프로젝트 2단계

요구사항을 굵은 글씨로 표현

  • Account를 구조체에서 클래스로 변경
    class Account{
    private:
        int id;
        int balance;
        char *name;
        Account(int id, int balance, char *name) {
            this->id = id;
            this->balance = balance;
            this->name = new char[::strlen(name) + 1];
            ::strcpy(this->name, name);
        }
    public:
        Account() {
    
        }
    		~Account() {
    		  delete []name;
    		}
        static Account Of(int _id, int _balance, char* _name) {
            return Account(_id, _balance, _name);
        }
        bool IsSame(int id) {
            return this->id == id;
        }
        void Deposit(int money) {
            this->balance += money;
        }
    
        void Withdraw(int money) {
            if (this->balance < money) {
                cout << "잔액부족\n";
                return;
            }
            this->balance -= money;
            cout << "출금완료\n";
        }
        void ShowInfo() {
            cout << "계좌ID: " << id << "\n";
            cout << "이 름: " << name << "\n";
            cout << "잔 액: " << balance << "\n";
        }
        Account* Copy() {
            return new Account(this->id, this->balance, this->name);
        }
    };
  • Account에서 char형 배열로 고객의 이름을 저장하던것을 문자열 포인터로 변경
    • 위 코드 참고
  • 구조체 배열을 포인터 배열로 변경
    class Accounts {
    private:
        static const int SIZE = 100;
        Account *accounts[SIZE];
        int index = 0;
        Account& Find(int id) {
            for (int i = 0; i < index; i++) {
                if (accounts[i]->IsSame(id)) { //기존코드: accounts[i].IsSame(id)
                    return *accounts[i]; //기존코드: accounts[i]
                }
            }
        }
    public:
        void Make() {
            int id, balance;
            char name[20];
    
            cout << "[계좌개설]\n";
            cout << "계좌ID: ";
            cin >> id;
            cout << "이 름: ";
            cin >> name;
            cout << "입금액: ";
            cin >> balance;
    
            Account account = Account::Of(id, balance, name);
            accounts[index++] = account.Copy(); //기존코드: account
            cout << "\n";
        }
    
        void Deposit() {
            int id, money;
    
            cout << "[입   금]\n";
            cout << "계좌ID: ";
            cin >> id;
            cout << "입금액: ";
            cin >> money;
            Account& account = Find(id);
            account.Deposit(money);
            cout << &account << "\n";
            cout << &accounts[0] << "\n";
            cout << "입금완료\n\n";
        }
    
        void Withdraw() {
            int money;
            int id;
            cout << "[출   금]\n";
            cout << "계좌ID: ";
            cin >> id;
            cout << "출금액: ";
            cin >> money;
    
            Account& account = Find(id);
            account.Withdraw(money);
        }
        void Inquire() {
            for (int i = 0; i < index; i++) {
                accounts[i]->ShowInfo();
            }
        }
    };
  • 구현하며 발생한 문제

    • 객체 배열을 포인터 배열로 변경하면서 주소값을 저장하도록 함.

    • 그리고 계좌 생성 후 입금을 테스트 해봄

    • 예상했던 결과는 입금까지 수행했을 때 총 금액이 200이 되는 것

    • 입금 처리를 위해 id로 계좌 배열에서 계좌를 찾는데 계좌 배열에 저장된 값이 이상하게 나옴

    • id는 115, balance는 150, name은 test가 되어야함

    • 기존코드에서 정상 동작했던 이유는 배열에 객체를 저장할 때 새로운 객체가 생성되어 저장이 되기 때문에 Make() 함수가 리턴되어서 Account 객체 메모리가 반환되더라도 괜찮았던 것.

        void Make() {
                int id, balance;
                char name[20];
      
                cout << "[계좌개설]\n";
                cout << "계좌ID: ";
                cin >> id;
                cout << "이 름: ";
                cin >> name;
                cout << "입금액: ";
                cin >> balance;
      
                Account account = Account::Of(id, balance, name);
                cout << &account << endl;
                accounts[index++] = account;
                cout << &accounts[0] << endl;
                cout << "\n";
            }

  • accounts 배열이 올바른 값을 가지고 있는것을 확인할 수 있음

  • 하지만 포인터 배열로 변경하면 새로운 객체가 아니라 객체의 주소값이 저장되었을 때
    이미 사라진 메모리를 참조하기 때문에 원하는 값이 나오지 않았던 것.

profile
공부하고 알게 된 내용을 기록하는 블로그

0개의 댓글