오늘 공부한 내용📓
- C++
개념 공부
static 변수/함수 컴파일 에러 발생하는 문제
static 변수 사용 시, 객체를 생성하지 않고도 사용할 수 있다고 알고 바로 아래처럼 사용하였다.
Account::Account(void)
{
_nbAccounts = 0; //static
_totalAmount = 0; //static
_totalNbDeposits = 0; //static
_totalNbWithdrawals = 0; //static
_accountIndex = 0;
_amount = 0;
_nbDeposits = 0;
_nbWithdrawals = 0;
}
그런데 아래처럼 에러가 났다.
Undefined symbols for architecture x86_64:
"Account::_nbAccounts", referenced from:
Account::Account() in Account.o
Account::Account(int) in Account.o
Account::getNbAccounts() in Account.o
"Account::_totalAmount", referenced from:
Account::Account() in Account.o
Account::Account(int) in Account.o
Account::getTotalAmount() in Account.o
"Account::_totalNbDeposits", referenced from:
Account::Account() in Account.o
Account::Account(int) in Account.o
"Account::_displayTimestamp()", referenced from:
Account::Account(int) in Account.o
Account::displayAccountsInfos() in Account.o
Account::makeDeposit(int) in Account.o
Account::makeWithdrawal(int) in Account.o
Account::displayStatus() const in Account.o
Account::~Account() in Account.o
"Account::_totalNbWithdrawals", referenced from:
Account::Account() in Account.o
Account::Account(int) in Account.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
구글링 해보는데,
Account::Account(void)
{
Account::_nbAccounts = 0; //static
Account::_totalAmount = 0; //static
Account::_totalNbDeposits = 0; //static
Account::_totalNbWithdrawals = 0; //static
_accountIndex = 0;
_amount = 0;
_nbDeposits = 0;
_nbWithdrawals = 0;
}
이렇게 고쳐보라는 글이 있어 해봤지만 에러는 똑같았다..
그러다 stack overflow 에서 또 다른 방법을 찾았고, 시도해보니 static 변수에 대한 에러 고치기는 성공!
참고링크 : static variable link error
int Account::_nbAccounts;
int Account::_totalAmount;
int Account::_totalNbDeposits;
int Account::_totalNbWithdrawals;
// void Account::_displayTimestamp();
cpp 파일 상단에, 먼저 static 변수들을 정의해주었다.
왜 먼저 정의해줘야 하는지 찾아보니,
hpp 파일에서 선언한 static 변수는 단순히 컴파일러에게 변수의 정보만을 주며, 실제로 메모리를 할당하지는 않는다.
//MyClass.hpp
class MyClass {
private:
static int a;
}
그렇기 때문에 cpp 파일의 전역 범위에서 정의하여 메모리가 할당되도록 해야하는 것!
객체 생성 전에 쓸 수 있다는 특징 때문에 그냥 냅다 써도 되는구나라고 생각했었는데, 객체 생성 전 ‘정의’를 해두어야 쓸 수 있는 거였다.
//MyClass.cpp
static int a = 0;
위 내용에 연결시켜, 전역 범위에서 정의(즉 초기화) 시켜야하기 때문에 생성자 안에서도 초기화할 수 없다!
생성자 안에서 초기화하고 있었는데 이것도 수정해야겠다.
C++ Chapter 8.10 : static 정적 멤버 변수
⬆️ 많은 도움이 된 블로그
그렇지만 위 방법으로도 static 함수는 에러 발생 중,,
‘멤버 함수 "Account::_displayTimestamp"을(를) 해당 클래스 외부에서 다시 선언할 수 없습니다.’ 라는 에러가 난다.
다른 방법을 찾아야할 것 같다.
void Account::_displayTimestamp(void)
{
time_t now;
char buf[17];
time(&now);
strftime(buf, sizeof(buf), "[%Y%m%d_%T%M%S]", localtime(&now));
std::cout << buf;
}
위 코드처럼 static 함수 정의 시, 클래스명을 기재해주니 해결되었다!!
static 변수 해결방법처럼 전역범위에 먼저 정의해줄 필요는 없지만, 다른 함수와 마찬가지로 클래스 이름을 사용하여 정의해야하는 거였다.
소멸자 index 역순으로 실행되는 이유
cpp00 ex02 실행 시켜보면, 소멸자에서 index 가 역순으로 실행된다.
[20230531_163719] index:7;amount:8942;closed
[20230531_163719] index:6;amount:106;closed
[20230531_163719] index:5;amount:23;closed
[20230531_163719] index:4;amount:1245;closed
[20230531_163719] index:3;amount:430;closed
[20230531_163719] index:2;amount:864;closed
[20230531_163719] index:1;amount:785;closed
[20230531_163719] index:0;amount:47;closed
예제대로라면, 0 부터 7 순서로 가야하는데!
블로그에 검색해보고 Bard에게 질문해보니, 소멸자가 인스턴스의 메모리를 해제하기 전에 모든 리소스를 정리하기 때문이라고 한다.
A클래스의 멤버로 B클래스가 있다면, 생성되는 순서는 A → B 이다.
소멸은 반대로 B → A 순서로 된다.
C를 기준으로 생각해보면,
구조체 포인터 내에 포인터가 있다면, 포인터를 먼저 free 해주고 구조체 포인터를 free 하는 개념인 것 같다.
함수 뒤 const의 역할
int checkAmount( void ) const;
void displayStatus( void ) const;
위 코드처럼 함수 끝에 const가 붙은 경우가 있었다.
구글링해보니, 이 함수 안에서 어떤 변수도 바꿀 수 없도록 사용하는 키워드라고 한다.
(mutable 은 예외라고 함)
클래스 멤버 함수의 경우에만 함수 뒤에 const 를 붙일 수 있고, 다른 const 함수만 호출이 가능하다.
이러한 기능으로, getter 함수나 bool 반환값처럼 값을 받아오거나 비교만 하는 경우에 많이 사용한다고 한다.
캡슐화
- 정의
- 데이터와 데이터를 처리하는 로직을 한 곳에 묶어 캡슐처럼 사용하게 하는 것으로, 데이터를 보호하고, 프로그램의 복잡성을 줄이고, 재사용성을 높이기 위한 목적이다.
- 클래스의 접근지정자인 private 과 public 을 사용하여 캡슐화를 구현하는데, 일반적으로 멤버 변수는 private, 멤버 함수는 public 으로 설정한다.
- 하지만 정확한 캡슐화는 모든 멤버 함수를 public으로 설정하는 것이 아니라, 외부에서 호출될 일 없는(멤버 함수에서만 호출되는) 함수 또한 private 으로 설정하는 것이 정확하다.
어려웠던 내용😢
static 변수와 static 함수를 사용하는 부분이 참 어려웠다. 발생한 에러와 static 을 구글링 해보며 발견한 내용으로 코드를 수정해가며 컴파일 했지만, 여전히 에러가 고쳐지지 않는 부분이 힘도 빠졌다. 하지만 나의 승부심을 자극해 끈질기게 매달렸고, 혼자 힘으로 해결했다는 점이 기분이 아주 좋았다!
나는 캡슐화를 단순히 ‘재사용할 수 있는 함수를 만드는 것’으로 알고 있었고, private에 멤버 변수를 public에 멤버 함수를 넣는 것으로 개념을 파악했었다. 드디어 cpp00을 평가 받았는데, 평가자로 오신 분께서 캡슐화의 정의와 접근지정자 설정 방법을 알려주셨다. 아쉽게 90점을 받게 되었지만, cpp 공부 초반에 중요하고 바탕이 되는 개념을 잘 잡을 수 있었던 것 같아서 다행이라고 생각한다!
제가 공부한 내용을 기록하고 있습니다.
혹시 수정이 필요한 부분이 있다면, 댓글로 지적 부탁드립니다!
선한 관심과 도움 감사드립니다😊
'TIL::Today I Learn' 카테고리의 다른 글
[TIL] 20230616 (0) | 2023.06.17 |
---|---|
[TIL] 20230601 (0) | 2023.06.02 |
[TIL] 20230530 (0) | 2023.05.31 |
[TIL] 20230529 (1) | 2023.05.30 |
[TIL] Description (0) | 2023.05.30 |