~는 내가 쓰던 코드에서 선언한 타입이었다. ~에는 쓴 코드에서 사용한 연산자와 타입이 올 것이다.
에러에 관한 이야기를 하기 전에 짚고 넘어 가야 할 중요한 사실이 있는데 C++에서 const를 요구하는 인자에 non-const를 넘기는 것은 괜찮지만 non-const를 요구하는 곳에 const를 쓰면 에러가 생긴다(https://erlerobotics.gitbooks.io/erle-robotics-cpp-gitbook/content/advanced_topics_i/const_and_non-const.html)
예를 들어서 우리가 흔히 쓰는 복사 생성자는 인자로 const reference 타입을 받지만 인자로 넘겨줄 객체를 const로 선언하지 않아도 에러가 생기지 않는다. 예를 들어서
class A
{
public:
A()
{
}
A(int _Num) :
Num(_Num)
{
}
A(const A& a)
{
std::cout << "Copy Constructor" << std::endl;
Num = a.Num;
}
~A()
{
}
public:
int Num;
void func()
{
std::cout << "func" << std::endl;
}
};
int main()
{
A a(3);
A aa = a;
}
여기서는 복사 생성자 인자로 객체 a를 넘겨줬는데 a는 const로 선언된 객체가 아님에도 에러가 생기지 않는다(물론 a객체를 const로 선언해도 가능하다) 하지만 문제는 non-const를 요구하는 func() 함수를 const 객체가 호출하면 문제가 된다. 예를 들어서
class A
{
public:
A()
{}
A(int _Num) :
Num(_Num)
{}
A(const A& a)
{
std::cout << "Copy Constructor" << std::endl;
Num = a.Num;
}
~A()
{}
public:
int Num;
void func()
{
std::cout << "func" << std::endl;
}
};
int main()
{
const A a(3);
a.func();
}
이렇게 사용하면 에러가 생긴다.
이러한 사실을 염두에 두면 제목에 나온 에러를 처리할 수 있는데 내가 저런 에러를 마주하게 된 상황은 아래와 같다.
#pragma once
template <typename T>
class CSharedPtr
{
public:
CSharedPtr() :
m_Ptr(nullptr)
{
}
CSharedPtr(T* Ptr)
{
m_Ptr = Ptr;
if (m_Ptr)
m_Ptr->AddRef();
}
CSharedPtr(const CSharedPtr<T>& Ptr)
{
m_Ptr = Ptr.m_Ptr;
if (m_Ptr)
m_Ptr->AddRef();
}
~CSharedPtr()
{
if (m_Ptr)
m_Ptr->Release();
}
private:
T* m_Ptr;
public:
void operator = (T* Ptr)
{
if (m_Ptr)
m_Ptr->Release();
m_Ptr = Ptr;
// 새로 지정된 레퍼런스 객체가 있을 경우 카운트를 1 증가시켜준다.
if (m_Ptr)
m_Ptr->AddRef();
}
void operator = (const CSharedPtr<T>& Ptr)
{
if (m_Ptr)
m_Ptr->Release();
m_Ptr = Ptr.m_Ptr;
if (m_Ptr)
m_Ptr->AddRef();
}
bool operator == (T* Ptr) const
{
return m_Ptr == Ptr;
}
bool operator == (const CSharedPtr<T>& Ptr) const
{
return m_Ptr == Ptr.m_Ptr;
}
bool operator != (T* Ptr) const
{
return m_Ptr != Ptr;
}
bool operator != (const CSharedPtr<T>& Ptr) const
{
return m_Ptr != Ptr.m_Ptr;
}
operator T* ()
{
return m_Ptr;
}
T* operator -> ()
{
return m_Ptr;
}
};
class CGameObject :
public CRef
{
public:
CGameObject();
CGameObject(const CGameObject& obj);
virtual ~CGameObject();
protected:
std::list<CSharedPtr<CCollider>> m_ColliderList;
.
.
.// 여러가지 다른 멤버 함수/변수들
};
CGameObject::CGameObject(const CGameObject& obj)
{
*this = obj;
if (obj.m_Animation)
m_Animation = obj.m_Animation->Clone();
m_Animation->m_Owner = this;
m_ColliderList.clear();
auto iter = obj.m_ColliderList.begin();
auto iterEnd = obj.m_ColliderList.end();
for (; iter != iterEnd; ++iter)
{
m_ColliderList.push_back((*iter)->Clone());
}
}
CGameObject의 복사 생성자의 obj인자는 const 객체이다. 따라서 obj의 멤버 변수인 m_ColliderList와 m_ColliderList안에 들어있는 CSharedPtr<CCollider>들도 const인 셈이다. 그런데 이 for문 내에서 CSharedPtr의 화살표 연산자(->)는 const를 요구하지 않는 멤버 함수이다. 이 멤버 함수를 const CSharedPtr<CCollider>로 호출하면 에러가 생길 수 밖에 없다.
따라서 에러를 해결하려면 아래와 같이 CSharedPtr의 화살표 연산자(->)끝에 const를 붙여주면 된다.
T* operator -> () const
{
return m_Ptr;
}
'공부 > 그 외' 카테고리의 다른 글
객체 지향 프로그래밍(OOP) (0) | 2022.09.11 |
---|---|
Visual Studio 문자 집합 사용(유니코드, 멀티바이트) (0) | 2021.12.08 |
레지스터(Register) vs 레지스트리(Registry) (0) | 2021.08.18 |
C7510 : 종속적 형식 이름은 'typename' 접두사와 함께 사용해야 합니다. (1) | 2021.08.12 |
꼬리 재귀(Tail recursion) (0) | 2021.08.04 |