C++ Chapter 8.9 : 클래스와 const
카테고리: Cpp
태그: Cpp Programming
인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 C++ 강의를 듣고 정리한 필기입니다. 😀
🌜 [홍정모의 따라 하며 배우는 C++]강의 들으러 가기!
chapter 8. 객체 지향의 기초 : 클래스와 const
🔔 const 가 붙은 객체
const Friend f;
f.setValue(2); // 💥에러! 불가능
f.getValue(2); // 💥에러! 불가능
- 객체 선언시
const
가 붙는 것의 의미- Friend 타입의 객체 f의 멤버의 값을 바꿀 수 없다.
- 따라서 setter 접근 함수 사용이 불가능 해진다.
- 근데 의외로 getter는 멤버의 값을 바꾸지 않는데도 불구하고 getter 접근 함수의 사용도 불가능해진다.
- 멤버를 바꾸지 않는 것을 확실히 하는 const 멤버 함수만 사용 가능하기 때문!
- 컴파일러는 멤버 값을 바꿨는가 아닌가로 판단하는 것이 아닌 멤버 함수가 const인가 아닌가로 판단한다.
- Friend 타입의 객체 f의 멤버의 값을 바꿀 수 없다.
뒤에 const가 붙은 멤버 함수만 사용 가능
객체를 생성할 때 const를 붙이면 멤버 값을 변경하는게 불가능하다. 그리고 이 객체는 const가 붙은 멤버 함수만 사용할 수 있다.
뒤에
const
가 붙을 수 있는건 멤버 함수만 가능하다. 일반 전역 함수는 뒤에const
를 붙일 수 없다.
int getValue() const
{
return m_value;
}
const Friend f;
f.setValue(2); // 💥에러! 불가능
f.getValue(2); // ⭐이제 가능⭐
멤버 함수 이름 뒤에 const
를 붙여 멤버 값을 변경하지 않을 것이라는걸 확실히 해준다. 객체가 const
로 생성되었을시 const
가 붙은 멤버 함수만 사용할 수 있다. setter 함수는 그 자체로 멤버의 값을 변경하는 함수기 때문에 const 멤버 함수로 만들 수 없다. const 붙여도 오류가 난다.
const
가 붙지 않은 일반 객체도const
멤버 함수를 호출할 수 있다. (호출 못 할거라고 착각했었다 😥) 단,const
가 붙은 객체는const
멤버 함수만 호출할 수 있다.- 매개 변수가
const
객체인 함수들은 인수로 받은 해당 객체의 멤버 함수를 사용할 때 꼭 뒤에 const가 붙은 함수만 사용할 수 있게 된다.- 함수에 인수로 객체를 넘길 때, 그 안에서 사용될 일이 있는 멤버 함수라면 뒤에
const
를 붙여주어야 한다. - getter 같은 접근 함수는 많이 사용되고 또한 멤버 값을 변경하지 않기 때문에 그냥 뒤에 const를 붙여서 구현해주자.
- 함수에 인수로 객체를 넘길 때, 그 안에서 사용될 일이 있는 멤버 함수라면 뒤에
🔔 복사 생성자
📜Something 클래스
class Something
{
public:
int m_value = 0;
Something()
{
cout << "Constructor" << endl;
}
void setValue(int value) { m_value = value; }
int getValue() const { return m_value; }
};
📜main
void print(Something st)
{
cout << &st << endl;
cout << st.m_value << endl;
}
int main()
{
Something something;
cout << &something << endl;
print(something);
return 0;
}
💎출력💎
Constructor
0x7fff7fbdd2fc // &st 와
0x7fff7fbdd2dc // &something 은 주소가 다르다.
0
print(something)
이 호출하면서 print 함수의 매개변수 st 에 메인 함수에서 생성된 something 객체가 복사된다.- 매개 변수이자 지역 변수인 Something st도 Something 객체로서 생성된다.
- Something 객체가 2번 생성되니 생성자도 2번 호출되야 한다.
- Something something; (메인 함수)
- Something st = something; (print 함수의 매개변수)
- 그러나 “Constructor”가 1번 출력되는 것을 보니 생성자가 한번만 호출됐다는 것을 알 수 있다.
- 이유는 매개 변수에 복사되는 Something st = something 이 실행될 때 클래스에 디폴트로 숨겨져 있던
복사 생성자
가 호출되었기 때문이다.
- 이유는 매개 변수에 복사되는 Something st = something 이 실행될 때 클래스에 디폴트로 숨겨져 있던
Something (const Something & st_in) // 복사 생성자
{
m_value = st_in.m_value; // 멤버 복사
}
- Something st = something;
- Call by Value 형태로 something 을 전달한다.
- 매개 변수인 Something st 객체가 생성되면서 복사 하는 같은 타입의 대상이 있기에 복사 생성자가 호출된다.
- st_in 은 복사 없이 something 그 자체를 참조한다. (Call by Reference)
- st_in.m_value, 즉 something 객체의 m_value 멤버 값을
- st 객체의 멤버 m_value 에 대입(복사)한다.
클래스는 모두 const이자 같은 타입의 객체를 참조로 인수 1개를 받아 그 멤버들의 값을 내 멤버들에 복사하는
복사생성자
를 디폴트로 가지고 있다. 숨겨져서 안보일 뿐!
- 즉 객체가 생성될 때 같은 타입의 객체의 멤버를 복사하여 멤버를 초기화한다.
const
- 복사하는 대상인 객체의 멤버 값을 변경할 수 없다.
- 복사하는 대상인 객체의 const 멤버 함수에만 접근이 가능하다.
- 같은 타입의 객체 그 자체(참조)를 가져와 복사한다.
디폴트로 있긴 하지만 아래 코드와 같이 프로그래머가 직접 복사생성자를 정의할 수도 있다.
class Something
{
public:
int m_value = 0;
Something(const Something& st_in) // 복사 생성자를 직접 정의했다.
{
m_value = st_in.m_value;
cout << "Copy constructor" << endl;
}
Something()
{
cout << "Constructor" << endl;
}
void setValue(int value) { m_value = value; }
int getValue() const { return m_value; }
};
void print(Something st)
{
cout << &st << endl;
cout << st.m_value << endl;
}
int main()
{
Something something;
cout << &something << endl;
print(something);
return 0;
}
💎출력💎
Constructor
0x7ffd1a921798
Copy constructor
0x7ffd1a92179c
0
복사 생성자가 호출되는 것을 확인할 수 있다.
void print(const Something & st)
{
cout << &st << endl;
cout << st.m_value << endl;
}
위와 같이 매개변수 타입을 바꿔주면 Something이 st에 복사되는 것이 아닌 st 가 Something 객체 그 자체를 참조하게 되므로 복사 생성자가 호출되지 않는다. 복사 과정이 없으므로!
복사 생성자가 호출될 때
- 먼저 생성한 객체를 나중에 생성한 객체의 생성자 인자로 전달할 때
- 함수의 인자로 객체를 Call by Value 형태로 전달할 때
- 객체를 Call by Value 형태로 리턴할 때
🔔 const 함수의 오버로딩
만약 동일한 함수가 2개 있는데 하나는 const를 붙이고 하나는 const를 붙이지 않았다면 어떻게 오버로딩이 될까?
#include <iostream>
#include <string>
class Something
{
public:
string m_value = "default";
const string & getValue() const
{
cout << "const version" << endl;
return m_value;
}
string & getValue()
{
cout << "non-const version" << endl;
return m_value;
}
}
int main()
{
Something s1;
s1.getValue(); // string & getValue() 호출
const Something s2;
s2.getValue(); // const string & getValue() const 호출
}
const string & getValue() const
- 리턴 타입 :
const string &
- 리턴 되는 m_value 의 레퍼런스를 리턴한다.
- 임시 공간에 복사 하는 과정 없이 그대로 리턴한다.
- const 레퍼런스 이므로 리턴 되는 string 값을 수정할 수 없다.
- s2.getValue() = 20 불가능.
- 리턴 되는 m_value 의 레퍼런스를 리턴한다.
- 뒤에
const
가 붙었으므로- 멤버 값을 변경할 수 없으며
const
객체의 경우 이 함수만 호출할 수 있다.
const 의 유무도 오버로딩의 고려 대상이 된다.
- 일반 객체로 생성된 s1은
- *s1.getValue() 호출시
- string & getValue() 를 오버로딩한다.
const 객체
로 생성된 s2은- *s2.getValue() 호출시
- const string & getValue() const 를 오버로딩한다.
const 객체
는 뒤에 const가 붙은 함수를 오버로딩 한다.
보통 멤버 함수를
const
로 만들 땐 리턴 타입도const
로 한다. const string & getValue() const
- const가 앞에 붙은 함수
- 단순히 리턴을 변경할 수 없는 상수로 하겠다는 의미
- const가 뒤에 붙은 함수
- const 객체만 사용할 수 있는 함수로서
- 멤버 값을 변경하지 않겠다는 의미
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기