일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- suffix return type
- virtual function table
- constructor
- vector size
- base from member
- std::vector
- virtual inheritance
- virtual destructor
- std::cout
- vector capacity
- member function pointer
- std::ostream
- std::endl
- diamond inheritance
- dynamic_cast
- virtual function
- conversion constructor
- c++ multi chatting room
- 더 지니어스 양면포커
- placement new
- this call
- pointer to member data
- C++
- c++ basic practice
- return by reference
- increment operator
- delete function
- new&delete
- discord bot
- operator overloading
- Today
- Total
I'm FanJae.
[c++] const member function, mutable 본문
※ 본 포스트는 코드누리 C++ Basic 강의 내용을 보고 정리한 포스트입니다.
1. const 객체에서 발생할 수 있는 문제점
#include <iostream>
class Point
{
public:
int xpos, ypos;
Point(int x, int y) : xpos{x}, ypos{y} {}
void set(int x, int y)
{
xpos = x;
ypos = y;
}
void print()
{
std::cout << xpos << ", " << ypos << std::endl;
}
};
int main()
{
Point pt(1, 2);
pt.xpos = 10;
pt.set(10, 20);
pt.print();
}
- 테스트를 위해 public에 멤버 데이터를 둔 상태이다.
- 사실 이 예제는 아무런 문제가 없다. (실행만 생각한다면 말이다.)
- 이때 객체를 const로 만들때 상황을 생각해보면, 아래와 같은 문제가 발생한다.
1-1. print()와 같은 값을 바꾸지 않는 함수도 에러 발생
#include <iostream>
class Point
{
public:
int xpos, ypos;
Point(int x, int y) : xpos{x}, ypos{y} {}
void set(int x, int y)
{
xpos = x;
ypos = y;
}
void print()
{
std::cout << xpos << ", " << ypos << std::endl;
}
};
int main()
{
const Point pt(1, 2);
pt.xpos = 10; // error
pt.set(10, 20); // error
pt.print(); // error?
}
- main에서 상수 객체를 선언했을때, 직접 값을 바꾸는 행위나 멤버 함수를 통해 값을 바꾸는 시도를 했다.
- 이는 당연히 에러가 발생해야 하는데 반해, print()도 에러가 발생하는 것을 확인할 수 있다.
- 왜 이런 문제가 발생할까?
- 이러한 이유는 하나의 클래스를 각각 구현과 선언으로 했을때로 생각해야 한다.
Point.h
class Point
{
public:
///
void print();
}
Point.cpp
void Point::print()
{
}
#include "Point.h"
int main()
{
const Point p1(1,2);
pt.print(); // error
}
- 컴파일러는 함수의 선언부를 보고 함수 호출 여부를 결정한다.
- 즉, Point.h만 보고, 함수 호출 여부를 결정하는 것이지. 실제로 Point.cpp의 print()가 어떻게 구현되어있는지 알 수 없다.
- 하지만 이렇다고 하더라도 상수 객체 또한 print()와 같은 함수는 필요하다.
2. 상수 멤버 함수( const member function)
① 멤버 함수 괄호 () 뒤쪽에 const를 붙이는 문법
- 함수를 선언과 구현으로 분리할 경우 양쪽에 모두 붙여야 한다.
② 상수 멤버 함수에서는 멤버의 값을 변경하지 않겠다는 약속. 상수 멤버 함수 안에서는 모든 멤버는 상수로 취급된다. 멤버의 값을 변경하는 경우 컴파일 에러가 발생한다.
③ 상수객체는 상수 멤버 함수만 호출 할 수 있다.
#include <iostream>
class Point
{
public:
int xpos, ypos;
Point(int x, int y) : xpos{x}, ypos{y} {}
void set(int x, int y)
{
xpos = x;
ypos = y;
}
void print() const
{
// xpos = 10; // error
std::cout << xpos << ", " << ypos << std::endl;
}
};
int main()
{
const Point pt(1, 2);
pt.print(); // ok
}
- 위와 같이 void print() 뒤에 const를 붙여 상수 멤버 함수를 만들 수 있다.
class Rect
{
int x, y, w, h;
public:
Rect(int x, int y, int w, int h)
: x{x}, y{y}, w{w}, h{h} { }
// int getArea() { return w * h;} // 틀린 코드..
int getArea() const { return w * h;}
};
//void foo(Rect r) // call by value : 복사본 오버헤드
void foo(const Rect& r)
{
int area = r.getArea(); // ????
}
int main()
{
Rect r(1,1,10,10); // 상수객체 아님.
int area = r.getArea(); // ok.
foo(r);
}
- 이와 같은 형태로 상수 객체를 많이 사용한다.
- 여기서 중요한 부분은 (const Rect& r)과 같이 사용하는 것이 아주 중요하다.
- const 참조 객체를 만들었으니, 이도 상수 객체이다.
- 객체의 상태를 변경하지 않는 모든 멤버 함수는 반드시 상수 멤버로 만들어야 한다. 주로 getter가 많을 탠데 이러한, getter와 같은 멤버 함수는 반드시 상수 멤버 함수로 만들어야 한다.
④ 그외 유의 사항
#include <iostream>
class Number
{
int value;
public:
Number(int n) : value(n) {}
int& get() { return value;} // 1
int get() const { return value;} // 2
};
int main()
{
Number num(10);
const Number cnum(10);
cnum.get(); // 2번만 가능
num.get(); // 1번 호출, 없다면
// 2번 호출.
num.get() = 20; // ok
cnum.get() = 20; // error
}
- 동일 이름의 상수 멤버 함수와 비 상수 멤버 함수를 동시에 만드는 것도 가능하다.
- 이때, 상수 객체는 상수 멤버 함수만 호출이 가능하지만, 비상수 객체는 비 상수 객체를 먼저 호출하려고 시도하며, 비 상수 멤버 함수가 없다면 상수 멤버 함수를 호출하려고 한다.
3. Mutable
#include <iostream>
class Rect
{
int x, y, w, h;
mutable int cnt = 0;
public:
Rect(int x, int y, int w, int h)
: x{x}, y{y}, w{w}, h{h} { }
int getArea() const
{
// static int cnt = 0;
++cnt;
std::cout << cnt << std::endl;
return w * h;
}
};
int main()
{
Rect r1(1,1,10,10);
Rect r2(1,1,10,10);
r1.getArea();
r2.getArea();
r2.getArea();
}
- Mutable을 사용하면 const 멤버 함수 내에서도 특정 멤버 변수를 변경할 수 있도록 하는 것이 가능하다.
- 부득이하게 필요한 경우가 있다곤 하지만, const의 의미가 약해질 수 있기 때문에 신중하게 사용을 요한다.
'C++ > Basic' 카테고리의 다른 글
[C++] Copy Constructor (0) | 2024.08.19 |
---|---|
[C++] this, Reference return (1) | 2024.08.18 |
[C++] Static Member (0) | 2024.08.16 |
[C++] Explicit Constructor (0) | 2024.08.14 |
[C++] Member initializer list, Default member initializer (0) | 2024.08.14 |