[C/C++] undefined reference to ‘vtable for X’
C++ code를 build하다보면 virtual
keyword를 종종 사용하게 되는데, 간혹 다음과 같은 error를 볼 수 있다.
/tmp/ccBNrCln.o: In function `my_ns::Animal::Animal()': main.cpp:(.text._ZN5my_ns6AnimalC2Ev[_ZN5my_ns6AnimalC5Ev]+0x13): undefined reference to `vtable for my_ns::Animal' /tmp/ccBNrCln.o: In function `my_ns::Animal::~Animal()': main.cpp:(.text._ZN5my_ns6AnimalD2Ev[_ZN5my_ns6AnimalD5Ev]+0x13): undefined reference to `vtable for my_ns::Animal' /tmp/ccBNrCln.o: In function `my_ns::Cat::Cat()': main.cpp:(.text._ZN5my_ns3CatC2Ev[_ZN5my_ns3CatC5Ev]+0x20): undefined reference to `vtable for my_ns::Cat' /tmp/ccBNrCln.o: In function `my_ns::Cat::~Cat()': main.cpp:(.text._ZN5my_ns3CatD2Ev[_ZN5my_ns3CatD5Ev]+0x13): undefined reference to `vtable for my_ns::Cat' /tmp/ccBNrCln.o:(.rodata._ZTIN5my_ns3DogE[_ZTIN5my_ns3DogE]+0x10): undefined reference to `typeinfo for my_ns::Animal' collect2: error: ld returned 1 exit status
이는 virtual
keyword를 사용하고 난 뒤에 상속받은 class에서 해당 function을 구현해주지 않아 발생한 문제다. 아래 예시 코드를 보자.
#include <iostream> namespace my_ns { class Animal { public: explicit Animal() { std::cout << "Call Animal" << std::endl; } virtual ~Animal() {} virtual void bark (void) = 0; }; class Dog : public Animal { public: explicit Dog() { std::cout << "Call Dog" << std::endl; } virtual ~Dog() {} virtual void bark (void) { std::cout << "Wall Wall" << std::endl; } }; class Cat : public Animal { public: explicit Cat() { std::cout << "Call Cat" << std::endl; } virtual ~Cat() {} virtual void bark (void); }; }; int main() { my_ns::Dog dog; my_ns::Cat cat; return 0; }
위 코드를 보면 destructor와 bark
함수가 virtual
로 선언되어 있는데, Cat
class에선 bark
을 description 해주지 않았다. 그러나 log에선 bark
에 대한 정보는 따로 나와있지 않아서 debugging을 하는데 어려움이 있을 수 있다.
결론은 모든 virtual
function을 구현해줘야 해당 문제가 해결된다. 아래와 같이 코드를 수정하면 build가 정상적으로 된다.
#include <iostream> namespace my_ns { class Animal { public: explicit Animal() { std::cout << "Call Animal" << std::endl; } virtual ~Animal() {} virtual void bark (void) = 0; }; class Dog : public Animal { public: explicit Dog() { std::cout << "Call Dog" << std::endl; } virtual ~Dog() {} virtual void bark (void) { std::cout << "Wall Wall" << std::endl; } }; class Cat : public Animal { public: explicit Cat() { std::cout << "Call Cat" << std::endl; } virtual ~Cat() {} virtual void bark (void) { std::cout << "Nyaong Nyaong" << std::endl; } }; }; int main() { my_ns::Dog dog; my_ns::Cat cat; return 0; }