myString에 미리 크기를 할당 받는 새로운 생성자 추가
#include <iostream>
class myString
{
char* string_content; // 문자열 데이터를 가리키는 포인터
int string_length; // 문자열 길이
int memory_capacity;
public:
// capacity 만큼 미리 할당함.
myString(int capacity);
myString(const char* str);
};
myString::myString(int capacity)
{
string_content = new char[capacity];
string_length = 0;
memory_capacity = capacity;
std::cout << "Capacity : " << capacity << std::endl;
}
myString::myString(const char* str)
{
string_length = 0;
while (str[string_length++])
{
}
string_content = new char[string_length];
memory_capacity = string_length;
for (int i = 0; i != string_length; i++) string_content[i] = str[i];
}
void doSomethingWithString(myString s)
{
}
// 컴파일 가능
doSomethingWithString(myString("abc"));
// 컴파일 가능
// "abc"는 myString 타입은 아니지만 생성자 중 myString(const char* str)이 있으므로
// 컴파일러가 알아서 doSomethingWithString(myString("abc"))로 변환해서 컴파일 해줌
// -> 암시적 변환
doSomethingWithString("abc")
사용자의 실수로 doSomethingWithString 함수의 인자로 숫자를 전달하는 경우
컴파일러는 myString(int capacity)가 있으므로 오류로 판단하지 않음
// 컴파일 가능
// 컴파일러가 알아서 doSomethingWithString(myString(3))으로 변환해서 컴파일 해줌
doSomethingWithString(3);
즉, 사용자가 의도하지 않은 암시적 변환이 일어나게 됨
-> 'explicit'로 원하지 않는 암시적 변환을 할 수 없도록 컴파일러에게 명시 가능
#include <iostream>
class myString
{
char* string_content; // 문자열 데이터를 가리키는 포인터
int string_length; // 문자열 길이
int memory_capacity;
public:
// capacity 만큼 미리 할당함. (explicit 키워드)
explicit MyString(int capacity);
// 문자열로 부터 생성
MyString(const char* str);
// 복사 생성자
MyString(const MyString& str);
~MyString();
int length() const;
int capacity() const;
};
// 생략
void doSomethingWithString(myString s)
{
// Do something...
}
int main()
{
// 컴파일 오류 발생
doSomethingWithString(3);
}
explicit은 implicit의 반대로 명시적이란 뜻을 가지고 있음
explicit 선언 시 이 생성자를 이용한 암시적 변환을 수행하지 못하게 막을 수 있음
// explicit 키워드를 사용하지 않은 경우 컴파일 오류 없이 작동 가능
myString s = "abc"; // MyString s("abc")
myString s = 5; // MyString s(5)
// explicit 키워드를 사용한 경우 컴파일 오류 발생
myString s(5); // 허용
myString s = 5; // 컴파일 오류!
const 함수 내부에서는 멤버 변수들의 값을 바꾸는 것이 불가능
하지만 멤버 변수를 mutable로 선언하였다면 const 함수에서도 값 변경 가능
mutable -> 변이 가능한이라고 보면 됨
#include <iostream>
class A
{
mutable int data_;
public:
A(int data) : data_(data) {}
void DoSomething(int x) const
{
data_ = x; // 컴파일 에러 발생하지 않음
}
void PrintData() const { std::cout << "data: " << data_ << std::endl; }
};
int main()
{
A a(10);
a.DoSomething(3);
a.PrintData();
}
유저의 정보를 확인해서 캐쉬에 데이터를 넣어야 할 때
(유저의 정보는 읽기만 가능해야 하고, 캐쉬는 업데이트가 가능해야 함)
class Server
{
// .... (생략) ....
mutable Cache cache; // 캐쉬!
// 이 함수는 데이터베이스에서 user_id 에 해당하는 유저 정보를 읽어서 반환한다.
User GetUserInfo(const int user_id) const {
// 1. 캐쉬에서 user_id 를 검색
Data user_data = cache.find(user_id);
// 2. 하지만 캐쉬에 데이터가 없다면 데이터베이스에 요청
if (!user_data) {
user_data = Database.find(user_id);
// 그 후 캐쉬에 user_data 등록
cache.update(user_id, user_data); // mutable 사용하지 않으면 캐쉬 업데이트 불가
}
// 3. 리턴된 정보로 User 객체 생성
return User(user_data);
}
};