2015-12-08 4 views
1

У меня есть базовый класс шаблонов Vect, из которого получен VectDynamic.C++ - неопределенная ссылка на оператор базового класса

Базовый класс (Vect.h):

template <typename Elem> 
class Vect 
{ 
public: 
    virtual Elem& operator[](std::ptrdiff_t); 
}; 

производный класс (VectDynamic.h):

#include "Vect.h" 

template <typename Elem> 
class VectDynamic: public Vect<Elem> 
{ 
    std::size_t _dim; 
    Elem* _val; 
public: 
    explicit VectDynamic(std::size_t dim = 0): _dim(dim), _val(new Elem[dim]) {} 
    VectDynamic(std::size_t, const Elem&); 
    VectDynamic(const VectDynamic&); 
    Elem& operator[](std::ptrdiff_t) override; 
}; 

template <typename Elem> 
VectDynamic<Elem>::VectDynamic(std::size_t size, const Elem& e): 
    _dim(size), _val(new Elem[size]) 
{ 
    for (std::size_t i = 0; i < size; ++i) _val[i] = e; 
} 

template <typename Elem> 
VectDynamic<Elem>::VectDynamic(const VectDynamic& v): 
    _dim(v._dim), _val(new Elem[v._dim]) 
{ 
    for (std::size_t i = 0; i < v._dim; ++i) _val[i] = v._val[i]; 
} 

template <typename Elem> 
Elem& VectDynamic<Elem>::operator[] (std::ptrdiff_t i) 
{ 
    if (std::size_t(i) >= _dim) 
     throw std::out_of_range("VectDynamic : Index out of range"); 
    return _val[i]; 
} 

Когда я пытаюсь создать экземпляр производного класса, как это (магистральный. CPP):

#include "VectDynamic.h" 

int main() 
{ 
    VectDynamic<double> v1(5, 2); 

    return 0; 
} 

Я в конечном итоге, эта ошибка из обоих классов:
undefined reference to 'VectDynamic<double>::operator[](long)'

Теперь я знаю, что многие сообщения говорят об этой ошибке, но после нескольких часов поиска я не мог найти причин, почему это произойдет в моем случае.
Я не думаю, что ошибка возникла из того, как я включаю файлы, так как он не работает ни когда все находится в одном файле.

Я читал в сообщении this, что это может быть связано с неявным экземпляром базового класса, который продолжается, когда объявлен производный класс, поскольку методы базового класса еще не определены.

Как вы думаете, в чем проблема? Что было бы достойным обходным решением?

EDIT: Забыл добавить operator[] от ребенка, добавлено его сейчас (оно не вызывало ошибок, как это было в моем коде).

+0

Почему вы не '= 0 'на оператора декларации базового класса (так как вы, кажется, не хотят это определить)? – JSF

+0

Сделать 'Vect'' operator []' pure virtual? – Bathsheba

+0

Спасибо, оба исправили это, хотя я не понимаю, почему проблема не появилась раньше ... – Blublublub

ответ

0

Несмотря на то, что Vect<double>::operator[] никогда не будет вызван, базовая таблица vtable должна использоваться на мгновение во время построения производного объекта и, как вы заявили, базовая таблица vtable имеет указатель на этот неопределенный метод. Это нужно решить, добавив «= 0» (обычно называемый «чистый виртуальный») к объявлению базового метода.

Изменения в

template <typename Elem> 
class Vect 
{ 
public: 
    virtual Elem& operator[](std::ptrdiff_t)=0; 
}; 
+0

. Я помещаю ваш комментарий в ответ, так что я мог бы продвигаться с чистой совестью. – Bathsheba

+0

Можете ли вы рассказать о том, как сделать базовый класс чистым, что-нибудь изменит в определении дочернего 'operator []'? –

+0

@MarkB вы заметили объяснение, что Батшеба воспользовалась моим первым комментарием в ответ? Выполнение этой базовой функции pure действительно изменяет производную функцию, она изменяет базовую таблицу vtable. Полученный конструктор использует базовый конструктор, который использует базовую таблицу vtable. Исходная ошибка исходила из базы vtable. Это использование базы vtable ничего не делает и может быть удалено оптимизатором. Но в зависимости от его удаления неверно. – JSF

0

Из-за ошибки кажется довольно понятным, что вы просто не определили VectDynamic<double>::operator[]. Если вы не хотите, чтобы оператор [] просто удалял объявления функций. Если вы этого захотите, вам нужно будет его реализовать.

Обратите внимание, что поскольку это класс шаблонов, вы не можете реализовать оператор в исходном файле без заголовка.

И теперь, когда я сказал все это, позвольте мне также указать, что вы не выполняете правильное правило 0, 3 или 5, вы будете утечки памяти; есть причина, по которой вы не используете std::vector?

+0

Я не следую правилу три/пять/ноль в этом коде, потому что я только скопировал часть, которая вызвала мою проблему. Нет никакой особой причины, почему я не использую 'std :: vector', я просто использую то, что я использую, отлично работает для меня, поэтому я не чувствовал необходимости находить что-то еще. – Blublublub