2012년 2월 15일 수요일

[C++][클래스] 객체 레퍼런스를 인자로 받을때 const 사용시 에러발생 문제


// 다른 객체에서 정보 복사해오기
//void cStudentInfo::CopyInfo(const cStudentInfo& c)
void cStudentInfo::CopyInfo(cStudentInfo& c)
{
char* newID = c.GetID();
char* newName = c.GetName();
int newKorPnt = c.GetKorPoint();
int newEngPnt = c.GetEngPoint();
int newMatPnt = c.GetMatPoint();


SetID(newID);
SetName(newName);
SetKorPoint(newKorPnt);
SetEngPoint(newEngPnt);
SetMatPoint(newMatPnt);
}



위의 코드는 클래스 멤버함수의 정의부이다.
자신과 동일한 클래스 타입 객체 레퍼런스를 인자로 받아 내용을 복사하는 함수인데
인자에 const를 붙이면 Getxxx() 함수를 사용할때 아래와 같은 에러가 난다.



1>c:\documents and settings\baikanp\my documents\visual studio 2008\projects\120214\report.cpp(146) : error C2662: 'cStudentInfo::GetID' : 'this' 포인터를 'const cStudentInfo'에서 'cStudentInfo &'(으)로 변환할 수 없습니다.



const를 제거하면 정상적으로 빌드가 되며,
참고로 Getxxx() 함수는 단순히 멤버변수를 리턴하는 함수이다.








남쌤에게 문의한 결과,
const로 선언하면 cStudentInfo& c 가 절대 변하지 않는다는 보장을 해준 것인데, 
c.Getxxx() 함수를 사용할 때 임시객체의 생성과 소멸 등이 발생하여 객체에 변경이 생기기 때문에 에러가 나는 것이라 한다.
지금으로서는 확실히 이해가 안되지만 Getxxx() 함수를 사용하는 것이 객체에 변경을 가져온다는 것으로 이해면 될것같다.
아마도 에러메시지로 보건데, 객체에 암묵적으로 포함된 this 라는 포인터가 변경되는 것이 직접적인 에러의 원인인듯 하다.




해결법은 두가지이다. 
가장 위의 코드처럼 const를 제거하거나, 
또는 아래와 같이 Getxxx() 함수를 거치지 않고 직접 멤버변수를 복사하는 것이다.



void cStudentInfo::CopyInfo(const cStudentInfo& c)
{
char* newID = c.m_szID;
char* newName = c.m_szName;
int newKorPnt = c.m_nKorPoint;
int newEngPnt = c.m_nEngPoint;
int newMatPnt = c.m_nMatPoint;






여기서 또 한가지 재밌는 것은 위 멤버 변수들은 private 로 선언되어 있다는 것이다.
즉,  어떤 객체의 메소드는 같은 타입 다른 객체를 인자로 받았을 때 그  private 멤버변수를 자유롭게 접근할 수 있다는 것이다.
(예를 들어 복사 생성자의 경우도 함수 내부에서 타 객체의 멤버를 직접 접근하고 있다.)








※ 내용보충 (2012. 02. 16):
const 객체를 사용해서 const가 아닌 멤버함수를 호출하는 것은 불가능하다. 컴퓨터는 const가 아닌 멤버함수는 멤버변수의 값을 변경한다고 생각하기 때문이다(뇌를 자극하는 C++ p.599). 위 문제의 경우 Get 함수들을 아래와 같이 const 함수로 선언해주면 const 객체를 통해서 사용해도 에러가 생기지 않는다. 참고로 const 함수란 멤버변수의 값을 변경하지 않는 함수를 말한다.




char* cStudentInfo::GetID(void) const

댓글 1개:

  1. 해결 방법이 하나 더 있는데요
    const 가 아닌 걸 const에 넣어줘서 그래요
    그래서 GetXXX() 함수 선언할 때

    void GetApple() 대신

    void GetApple() const;

    이렇게 해주면 에러가 안 납니다

    답글삭제