본문 바로가기
컴퓨터/디버깅

cannot instantiate abstract class

by adnoctum 2010. 7. 26.


다음과 같은 에러 메세지가 떴다.

환경 : Visual C++ 9.0 (VS2008) on Windows XP SP3

\PerfusionCalculatorDLG.cpp(1950) : error C2259: 'IICGPerfusion2' : cannot instantiate abstract class

에러 메세지는 말 그대로 abstract class를 instantiation 시킬 수 없다는 의미이다. abstract class란 pure virtual function 을 갖는 class를 말하며, instantiation 이란 객체를 메모리에 실제로 올리는 것을 의미하는 것으로 알아도 무방하다. 각각에 대하여 좀 더 자세히 살펴 보자.


pure virtual function 이란 base class 작성시 선언만 해 놓을 뿐 정의는 하지 않는 함수를 의미한다. 실제 함수의 몸체를 작성하는 작업(즉, 정의)은 base class를 상속받은 클래스들에서 하게 된다. 순수가상함수의 문법은 다음과 같다.

virtual return_type function_name(paramter specification) = 0;


가장 마지막에 = 0; 을 표시하는 것이 핵심이라 하겠다. 그 한 예를 보면 다음과 같다.

    virtual bool GetResult(double **pPerfusionMap, double **TmaxMap) = 0;

왜 이런 것이 필요할까? 그것은, 상속받은 클래스에서 함수의 정의를 어떻게 하든 그 결과의 형태는 거의 변하지 않기 때문이다. 이처럼 고정된 형태의 함수로 추상화 시킬 수 있는 작업이라면 그 함수를 사용하는 부분과 함수를 정의하는 부분은 별도로 개발이 가능할 것이다. 실제로 COM 과 같은 개발방법에서 저와 같은 경우가 많이 사용된다고 한다. 그리고 때때로 저와 같은 순수가상함수를 interface라고 부르기도 하는데, 저 함수를 사용할 사용자와 저 함수를 개발할 개발자는 interface만 정해 놓으면 서로 완전히 독립적으로 개발을 할 수 있는 것이다.

   abstract class란 '적어도' 하나 이상의 pure virtual function 을 갖고 있는 클래스를 의미한다. 이런 클래스는 instantiation 될 수 없다. instantiation 이란 무엇인지 살펴 보자. instance란 곧 occurrence, 추상적으로 존재하는 것을 실제화시키는 것을 의미한다. C++과 같은 객체지향프로그래밍에서는 class를 정의 및 구현해 놓는 것을 '추상화'시켰다고 하며, 그것을 실제로 메모리에 올리는 것을 instantiation[각주:1] 이라는 것으로 많이 사용된다. 즉, 우리가 아무리 class의 정의를 해 놓는다고 하더라도 그것을 실제 코드 내에서 사용하지 않으면 그것은 결코 사용되지 않고, instantiation 되지 않는 것이다. 심지어 똑똑한 컴파일러들은 그런 객체는 아예 컴파일조차 하지 않는 경우도 있다[각주:2].

   그런데, abstract class는 결코 instantiation 시킬 수 없다. 왜냐 하면, pure virtual function 은 그 정의에 따라 그 어디에서도 그 클래스에 연결시킬 수 없기 때문이다. 즉, 객체가 instantiation 된다는 것은 그 객체가 갖고 있는 member variable들을 위한 공간을 할당하고, 그 객체가 갖고 있는 member function 들을 메모리에 올린 후 그 객체의 함수 테이블에다 각각의 함수에 대한 주소를 연결[각주:3]해 놓을 것이다. 그림으로 보자면 대략 다음과 같다.


CBase 클래스의 함수 aa는 정의된 것이 없기 때문에 가리킬 주소가 없고, 따라서 메모리에 올린다는 것이 무의미하다. 반면 CChild 는 갖고 있는 모든 함수의 구현이 메모리 상에 존재하고, 따라서 모든 함수가 그 주소를 갖고 있다. 이런 클래스라야 써먹을 수 있다는 얘기.


그런데 pure virtual function 의 경우, 그 정의에 따라, 함수의 정의가 존재할 수 없고, 따라서 그와 같은 객체는 메모리에 올려질 수 없다[각주:4]. 따라서 pure virtual function 을 갖고 있는 class인 abstract class들은 instantiation 될 수 없다.

   그런데 실제로 위와 같은 컴파일 에러 메세지는 abstract base class 때문에 나왔다기 보다는, 상속한 클래스에서 부모 클래스의 pure virtual function 을 overriding 하지 않았기 때문에 발생하는 경우가 잦아 보인다. 즉, pure virtual function 을 갖고 있는 클래스를 상속받으면 '반드시' 그 함수를 재정의해 주어야 한다, 사실 이것이 pure virtual function의 가장 큰 목적일 것이다. 그런데 깜빡 잊고 그 작업을 해주지 않으면 상속받은 클래스에서도 여전히 pure virtual function 을 갖고 있는 것이 되며, 결과적으로 상속을 받은 클래스 역시 abstract class가 된다. 그래서 위와 같은 컴파일 에러 메세지가 나온 것이다.

해결 방법은 간단하다. 깜빡한 pure virtual function 의 overriding 을 해주면 된다.






  1. instantiation 에 대한 명확한 정의는 없다. 사용자에 따라 적절한 의미를 재부여할 수도 있지만 일반적으로는 이 글에서 언급한 의미로 사용된다. [본문으로]
  2. 그래서 그런 class에 컴파일 오류가 있었다면, 아예 컴파일조차 되지 않기 때문에 오류 메세지가 나오지 않는 경우도 있다. [본문으로]
  3. 실제로 함수명이란 '함수 포인터'이다. [본문으로]
  4. 명확히는, 그렇게 하는 것이 '의미'적으로 더 나았기 때문에 그렇게 했을 것이다, 뭐, 다른 특별한 이유가 있다기보다는. 함수의 이름은 있지만 사용할 수 없는 함수를 소유하고 있는 객체를 만든다는 것은 무슨 의미가 있을까? [본문으로]

'컴퓨터 > 디버깅' 카테고리의 다른 글

R 사용하기 (초보)  (0) 2010.10.21
segmentation fault의 원인  (1) 2010.09.30
invalid operands of types  (0) 2010.06.12
디버깅 공지사항  (0) 2010.05.25
no matching function for call to  (0) 2010.05.24