현재 Chapter 8-8 프로젝트 안에는
Calc.h 헤더파일, 8-8 cpp(main file), Calc.cpp 이렇게 3개의 파일이 있다 가정해보자.
보통 헤더파일에는 우리가 prototype들만 넣어놓는다고 배웠다.
그래서 프로토타입들만 헤더파일에 넣어놨다.
main 함수에서 해당 클래스들을 사용하려면 당연히 내가 만들어놓은 헤더파일을 include해줘야겠지.
주의할 건 내가 만든 헤더파일은 < > 로 넣는게 아닌 , " " 로 넣어준다는 것!
그리고 클래스를 구현한 파일은 Calc.cpp로 따로 만들어놨다.
비쥬얼 스튜디오 내에선 프로젝트 단위로 컴파일이 진행되니, 컴파일을 하면 main함수가 담긴 cpp와 Calc.cpp가
같이 진행되겠지.
보통 우리가 처음 클래스를 헤더파일 내에서 구현하고, 프로토타입만 남겨두고 기능들은 다른 cpp에 넣어줄 때
편한 기능이 있다.
'Quick Actions and Refractorings' 를 누르고, Move definition Location을 눌러줌으로써 변경이 가능하다!
_____________________________________________________________________________________________________________________________
내가 오브젝트(instance)를 선언할 때 const로 선언한다면, 당연히 그 안의 값들을 변경할 수 없으니 오류가 난다.
그렇다면, 이런 의문이 들 수 있다.
그냥 something.getValue()함수는 그냥 값을 return 하는 거니까, 문제없지 않나? 싶은데 오류가 난다.
여기서 중요한 것.
'컴파일러가 const냐 아니냐를 판단할 때 그 안의 값이 바뀌냐 안바뀌냐로 판단하는 것이 아닌,
Member function이 const로 선언이 되었나 안되었나로 판단한다.'
그래서 해당 Member Function을 const로 선언해주니, 정상작동한다.
const int getValue()가 아니겠지? 이건 return type을 const int로 해준다는 이야기니까.
_____________________________________________________________________________________________________________________________
main 함수를 보자.
Something something; 을 함으로써, 생성자가 생성되서 "Constructor" 가 나왔다.
그 이후의 해당 instance의 주소를 출력해봤다.
그리고 print( ) 함수를 써봤다. 인자를 그냥 클래스로 줬기 때문에, call-by-value, 즉 값을 복사한다.
값을 복사한다는 이야기는, 새로 클래스를 만든다는 이야기인데, 생성자는 아까 처음 나오고 나오지 않았다.
왜그럴까?
결론부터 이야기하자면, 생성자 함수를 우리가 만들어주지 않아도 default로 있는 것처럼,
복사 생성자라는 것이 default로 있다. 즉 오버로딩이 된 것이다.
_____________________________________________________________________________________________________________________________
something의 객체를 하나는 일반적이게, 나머지 하나는 const로 처리해서 선언했다.
그러고 나서 getValue()라는 함수를 호출할 때
아까 글을 작성할 때 const 로 객체를 선언하면, const 처리가 되어있는 함수만 사용할 수 있다고 언급했다.
그렇기에 일반적인 함수는 사용할 수 없고, const 처리된 함수가 따로 필요하고
따로따로 오버로딩이 된 것을 확인할 수 있다.
이건 상식적으로 쉽게 납득간다.
당연히, st1 과 st2의 주소값은 다르겠지.
마찬가지로, st1에서 값을 변경했지만 이건 st1의 값을 변경한 것이지 st2의 값을 변경한 것은 아니기에 값이
다르다.
static이라는 키워드가 나왔다.
우리가 전에 C와 C++에서 static 키워드를 배울 때, static은 메모리에 올라가고 프로그램이 종료할 때까지
메모리를 반납하지 않고 유지한다 배웠다.
메모리에 올라간다는 것이 핵심인 것 같다.
클래스 내에서 static 변수를 선언하고 나서 바로 초기화가 불가능하다.
이유는 여러가지가 있는 것 같은데, 내가 납득한 이유는 이 클래스를 단순히 한 곳에서만 쓰이는 게 아니라 여러 곳에서 쓰일텐데 클래스가 여러 번 선언됨으로써 static 값을 여러 번 바꾸면 논리적으로 오류가 있겠지.
암기) 그래서 static 변수는 클래스 밖에서 따로 초기화를 해줘야한다.
또한, static 변수는 메모리에 올라가 쭉 유지가 된다 했다.
즉, 내가 객체를 따로 선언하지 않아도, static을 선언함과 동시에 이미 메모리에 올라갔기 때문에
주소값을 출력할 수 있다. static이기 때문에 주소값이 다 일치하겠지.
static 변수가 private으로 선언되었을 경우, main 함수에서 접근이 불가할 것이다.
그렇다고 일반적인 메소드로는 static 변수에 접근할 수 없다.
그렇기에 return 값이 static int인 메소드를 클래스에 만들었고 main 함수에서 접근하고 있다.
여기서 마찬가지로, static 이기에 , instance를 생성하지 않아도 메모리를 할당하므로
그냥 Something::getValue()로 해도 값이 출력된다.
여기서 static과 일반적인 변수의 차이점이 분명히 드러난다. 잘보자.
static 멤버함수는 this-> 가 불가하다.
왜 그럴까?
static 자체가 계속 말했다시피 클래스 내에 있는 느낌이라기보단, 독립적인, 메모리를 할당받는 변수이다.
그렇기에, instance에 종속되지 않기에 this->를 사용하지 못하고, 그냥 일반변수처럼 활용해야한다.
그렇기에, 객체 내의 일반적인 함수(메소드)를 포인터로 받을 땐, 클래스를 명시하면서 받아야한다.
int (Something::*ptr)() = &(Something::temp);
cout << (s2.*ptr)() << endl;
static int (*ptr)() = &(something::getValue);
cout << ptr() << endl;
static 멤버 변수는 생성자 내에서도 초기화가 불가하다.
아까랑 같은 이유다.
클래스 내에선 초기화가 불가하다.
그렇기에 트릭으로 주로 사용되는 방법이, 클래스 안에 클래스를 넣어주고 안쪽의 클래스 생성자가 static 변수의 값을 바꾸는 것이다.
좀 쉽게 private의 변수를 접근할 방법이 없을까? 하다가 나온 것이 friend 키워드다.
friend로 프로토타입을 넣어준다면, 추후 밖에서 함수에서 private의 변수를 접근할 수 있다.
절차지향이기에, class A는 class B를 아직 알지 못한다.
그런 상태에서, A와 B를 인자로 받는 함수를 구현하려하면, A 에선 friend 선언이 불가하다.
방법은, 다른 함수에서 했던 것처럼, 프로토타입을 위에 선언해주면 된다.
또, 실제 함수 구현은 밖에서 해주고, B의 함수를 나중 클래스인 A가 프로토타입으로 받는 방법도 있다.
'C++(따라하며 배우는 C++)' 카테고리의 다른 글
chapter 9-(2). 연산자 오버로 (0) | 2021.10.10 |
---|---|
Chapter 9-(1). 연산자 오버로딩 (0) | 2021.09.28 |
Chapter 8-(1). 객체지향의 기초 (0) | 2021.09.13 |
Chapter 7-(4). 함수 (0) | 2021.09.07 |
chapter 7-(3). 함수 (0) | 2021.09.06 |