This is one of those cases where I thought I understood C++ virtual methods reasonably well, and then an example comes along where I realise that, sadly, I don't. Is there anyone reading this who can make sense of the following?
Here is some test code in which I define a very simple base class (actually just a two-element struct), an abstract template class containing a virtual void method, and then a derived class which inherits from both of them and explictly overrides the virtual void method with a concrete method.
#include <string.h> // For memcpy
#include <vector> // For std::vector
struct int_array_C
{
int n;
int* contents;
};
template <typename T> class array_template
{
public:
array_template<T>() {}
array_template<T>(const array_template<T> &source)
{
*p_n = *(source.p_n);
setPointers(&(source.local_contents[0]));
}
// ..and in reality, a bunch of other array manipulation functions
protected:
virtual void setPointers(const T* data) = 0;
int *p_n;
std::vector<T> local_contents;
};
class int_array : public int_array_C, public array_template<int>
{
public:
int_array() : array_template<int>()
{
n = 0; contents = NULL;
}
protected:
virtual void setPointers(const int* data)
{
p_n = &n;
local_contents.resize(n);
memcpy(static_cast<void *>(&local_contents[0]),
static_cast<const void *>(data), n*sizeof(int));
contents = &local_contents[0];
}
};
int main()
{
int_array myArray;
int_array yourArray(myArray);
return 1;
}
When the copy constructor is called in the second line of main(), the argument is an instance of the derived class which has a concrete setPointers() method. Therefore, when the template class's copy constructor is called and the call to setPointers() is encountered, I'd expect the rules of polymorphism to kick in and the derived class's setPointers() method to be called.
In fact, however, the compiler chokes on this; at compilation time I get a warning saying
"Warning: call of pure virtual function at line 18"
and at link time the linker fails with a message saying
error LNK2019: unresolved external symbol "protected: virtual void __cdecl array_template<int>::setPointers(int const *)" (?setPointers@?$array_template@H@@MEAAXPEBH@Z) referenced in function "public: __cdecl array_template<int>::array_template<int>(class array_template<int> const &)" (??0?$array_template@H@@QEAA@AEBV0@@Z)
Exactly the same thing happens (with slight variation in the text of the error messages) using Visual C++ and Intel C++ on Windows and gcc on Linux, so it's obviously a genuine violation of language rules rather than just being a compiler quirk. Yet I can't see what the problem is.
So, what am I doing wrong and how might I make this work as intended?