Project Hub

4. implicit, explicit, mutable 키워드 본문

C++/c++ basic

4. implicit, explicit, mutable 키워드

safy 2022. 12. 21. 11:36
728x90
반응형

이전 글

2022.12.21 - [C++/c++ basic] - 3. copy consturctor

 

3. copy consturctor

이전 글 2022.12.21 - [C++/c++ basic] - 2. reference 2. reference 이전 글 2022.12.21 - [C++/c++ basic] - 1. namespace 1. namespace namespace(이름공간) 개체를 구분할 수 있는 범위를 나타내는 말 함수나 구조체 혹은 변수 이

projecthub.tistory.com

 

1. implicit conversion (암시적 변환)

 

아래와 같이 정의된 코드가 있다고 가정하자.

// CMyString 이라는 class 생성
// 여러 형태의 생성자 정의
 
class CMyString
{
public:
    CMyString(char szCharacter);
    CMyString(const char* pszString);
    CMyString(const CMyString& CopyConstructor);
 
    CMyString(int iCapacity);
 
    ~CMyString();
}
 
CMyString::CMyString(char szCharacter)
{
    m_String = new char[1];
    m_String[0] = szCharacter;
    m_StrLen = 1;
    m_memCapacity = m_StrLen;
}
 
CMyString::CMyString(const char* pszString)
{
    m_StrLen = strlen(pszString);
    m_String = new char[m_StrLen];
    m_memCapacity = m_StrLen;
 
    for (int i = 0; i < m_StrLen; i++)
        m_String[i] = pszString[i];
}
 
CMyString::CMyString(const CMyString& copyConstructor)
{
    m_StrLen = copyConstructor.m_StrLen;
    m_String = new char[m_StrLen];
    m_memCapacity = m_StrLen;
 
    for (int i = 0; i < m_StrLen; i++)
        m_String[i] = copyConstructor.m_String[i];
}
 
CMyString::CMyString(int iCapacity)
{
    m_String = new char[iCapacity];
    m_StrLen = 0;
    m_memCapacity = iCapacity;
    std::cout << "Capacity: " << iCapacity << std::endl;
}
// some codes................................
 
void DoSomethingWithString(CMyString s)
{
    // Do Something...
}


DoSomethingWithString(CMySting s) 함수를 아래와 같이 사용할 경우, 컴파일이 되는 과정을 확인해보면 아래와 같다.

DoSomethingWithString(CMyString("abc")); // 이렇게 사용할 경우는 당연히 컴파일이 성공한다.
 
// 이렇게 사용할 경우에는, "abc"가 CMyString 타입이 아니지만, CMyString 으로 바꿀 수 있는가를 찾는다.
// 생성자들 중에서 CMyString(const char* pszString); 이 존재하기 때문에 이것으로 변환된다.
//  DoSomethingWithString("abc");  =>   DoSomethingWithString(CMyString("abc"));  
DoSomethingWithString("abc");


아래와 같은 경우에도 오류가 발생하지 않는다.

// 아래와 같은 경우는 CMyString(int iCapacity); 라는 생성자가 있기 때문에 해당 생성자로 변환된다.
// DoSomethingWithString(3); => DoSomethingWithString(CMyString(3));
// 따라서 오류가 발생하지 않는다.
 DoSomethingWithString(3);


위의 내용과 같이 예상치 못한 경우에 암시적 변환이 일어날 수 있다.

 

2. explicit 키워드

암시적 변환을 할 수 없도록 컴파일러에게 명시
명시적

 

아래와 같이 explicit 키워드를 지정해주면, 암시적 변환이 일어나지 않는다.  

 

따라서 DoSomethingWithString(3); 에서 오류가 발생한다.

class CMyString
{
public:
    CMyString(char szCharacter);
    CMyString(const char* pszString);
    CMyString(const CMyString& CopyConstructor);
 
    explicit CMyString(int iCapacity);
 
    ~CMyString();
}
 
// ..........
 
void DoSomethingWithString(CMyString s)
{
    // Do Something...
}
 
int main()
{
    DoSomethingWithString(3); // error
}

아래와 같은 케이스에서도 explicit 키워드 유무에 따라 오류가 발생하거나, 발생하지 않는다.

// explicit 키워드가 없는 경우, 아래의 코드는 오류가 발생하지 않는다.
 
CMyString s = "abc"; // CMyString("abc");
CMyString v = 3; // CMyString(3);
 
// explicit 키워드가 있는 경우, 아래와 같이 선언해야 한다.
 
CMyString s("abc"); // CMyString("abc");
CMyString v(3); // CMyString(3);

 

 

3. mutable

변경 가능한
const 함수에서도 값을 변경 가능

 

아래와 같이 선언을 하였다면, 컴파일 오류가 발생한다.

이유는 DoSomething 함수가 const 함수이기 때문에 멤버 변수에 값을 대입하는 것이 불가능하기 때문이다.

#include <iostream>
 
class CMutable
{
public:
    int m_iData;
public:
    CMutable(int iData): m_iData(iData) {}
    void DoSomething(int iData) const {m_iData = iData;}                    // 불가능.
    void PrintData() const {std::out << "data: " << m_iData << std::endl;}
};
 
int main()
{
    CMutable mut(10);
    mut.DoSomething(4);
    mut.PrintData();
}


아래와 같이 수정한다면, cost 함수인 DoSomething 함수에서 멤버 변수에 값을 대입할 수 있다.

#include <iostream>
 
class CMutable
{
public:
    mutable int m_iData;
public:
    CMutable(int iData): m_iData(iData) {}
    void DoSomething(int iData) const {m_iData = iData;}                    // 가능
    void PrintData() const {std::out << "data: " << m_iData << std::endl;}
};
 
int main()
{
    CMutable mut(10);
    mut.DoSomething(4);
    mut.PrintData();
}


mutable이 필요한 이유는 아래와 같은 상황이 있을 수 있다.

서버가 데이터베이스에서 특정 유저를 조회한 후, 해당 유저의 정보를 리턴하는 경우가 있다고 하자.

해당 상황에서는 데이터베이스를 업데이트 하지도 않고, 

 

무엇인가를 수정하는 작업도 없기 때문에 const 함수로 선언을 한다.


그러나 속도를 위해 캐시를 둔 경우에 문제가 발생할 수 있다.

서버에서 캐시에 특정 유저를 조회하였으나 없는 경우, 데이터베이스에서 요청을 한다.

그리고 그 반환된 유저의 정보를 캐시에 저장해 놓고, 다음에 빠르게 접근할 수 있도록 하는데, 

 

이때 조회하는 함수가 const로 선언되었기 때문에 업데이트 작업을 수행할 수 없게 된다.

따라서 위와 같은 케이스에 mutable로 캐시를 선언하면 문제가 해결된다.

아래는 위와 같은 상황에 대한 코드 예시다.

class Server
{
    // .... (생략) ....
    mutable Cache cache;                        // mutable 로 캐시의 객체 선언.
 
    User GetUserInfo(const int user_id) const
    {
        Data user_data = cache.find(user_id);
         
        if (!user_data)
        {
            user_data = Database.find(user_id);
 
            cache.update(user_id, user_data);       // 문제가 발생했던 update 동작 수행 가능.
        }
 
        return User(user_data);
    }
};
728x90
반응형

'C++ > c++ basic' 카테고리의 다른 글

6. Wrapper 클래스 - 타입변환 연산자  (1) 2022.12.21
5. 연산자 오버로딩, friend 키워드  (1) 2022.12.21
3. copy consturctor  (0) 2022.12.21
2. reference  (0) 2022.12.21
1. namespace  (1) 2022.12.21
Comments