Вызов функции из производного класса шаблона

Мой базовый класс:

//Element.h
class Element
{
public:
Element();
virtual ~Element(){}; // not sure if I need this

virtual Element& plus(const Element&);
virtual Element& minus(const Element&);
};

Производный шаблонный класс:

//Vector.h
#include "Element.h"

template <class T>
class Vector: public Element {
T x, y, z;

public:
//constructors
Vector();
Vector(const T& x, const T& y = 0, const T& z =0);
Vector(const Vector& u);
...     
//operations
Element& plus(const Element&) const;
Element& minus(const Element&) const;
...
};
...

//summation
template <class T>
Element& Vector<T>::plus(const Element& v) const
{
const Vector<T>& w = static_cast<const Vector<T>&>(v);  
Vector<T>* ret = new Vector<T>((x + w.x), (y + w.y), (z + w.z));
return *ret;
}

//difference
template <class T>
Element& Vector<T>::minus(const Element& v) const
{
const Vector<T>& w = static_cast<const Vector<T>&>(v);
Vector<T>* ret = new Vector<T>((x - w.x), (y - w.y), (z - w.z));
return *ret;
}

У меня была другая проблема с этим кодом (ответ в другой пост), но в настоящее время я борюсь с тем, что если я попытаюсь запустить это, я получу

Неопределенные символы: «Element :: plus (Element const &)», ссылка на которую находится:
vtable для Vectorin main.o
«Element :: Element ()», ссылка на нее:
Vector :: Vector () в main.o
Vector :: Vector (double const &, double const &, double const &) в main.o
"Element :: minus (Element const &)", ссылка на который указана из:
vtable для Vectorin main. o
"typeinfo для элемента", ссылка на который есть:
typeinfo для Vectorin main.o
ld: символ (ы) не найден
collect2: ld вернул 1 статус выхода

Это потому, что производный класс шаблона не размещен в том же файле, что и базовый класс, и это вызывает проблемы с компилятором (аналогично тому, как мне пришлось определять весь класс Vector в файле заголовка)?

Я новичок в C ++ и все еще читаю, что такое vtables и как они работают, но пока не могу понять этого.


person Nick Sweet    schedule 20.06.2010    source источник
comment
Поскольку вы спросили, это тот случай, когда все общедоступные базовые классы должны иметь виртуальный деструктор, чтобы их можно было правильно удалить.   -  person GManNickG    schedule 20.06.2010
comment
@GMan: Пожалуйста, не говорите все общедоступные базовые классы в общем контексте, это действительно меня раздражает :) @Nick: Взгляните на Саттерса Виртуальность или, по крайней мере, его краткое содержание. Также обратите внимание, что это странно, что вы возвращаете экземпляры, выделенные кучей, в _1 _ / _ 2_, почему бы просто не создать их в стеке?   -  person Georg Fritzsche    schedule 20.06.2010
comment
@Georg: Почему бы и нет? :) Вы получаете неопределенное поведение, удаленное с помощью базового указателя без виртуального конструктора. Единственный способ действительно убедиться, что это не проблема, - не публиковать базу данных.   -  person GManNickG    schedule 21.06.2010
comment
@GMan: Хотя удаление с помощью базового указателя - это UB, не все базовые классы нуждаются в полиморфном удалении - зачем в таком случае навязывать это пользователю? Защищенный не виртуальный dtor тоже решает эту проблему.   -  person Georg Fritzsche    schedule 21.06.2010
comment
@Georg: Но тогда это не публично, и мой комментарий к нему неприменим. :)   -  person GManNickG    schedule 21.06.2010
comment
@GMan: Но вы говорили об общедоступных базовых классах, а не о dtors - я просто говорю, что не всем общедоступным базовым классам нужен виртуальный dtor. Или я что-то упустил?   -  person Georg Fritzsche    schedule 21.06.2010
comment
@Nick Sweet: Почему вы используете Element& plus(const Element&) в базовом классе, а Element& plus(const Element&) const в производном классе?   -  person Lazer    schedule 21.06.2010


Ответы (3)


Я думаю, что компилятор / компоновщик имеет в виду это, когда сообщает вам Undefined symbols: "Element::plus(Element const&)". Эти символы (плюс и минус для элемента) были объявлены, но не определены.

person Alexandros Gezerlis    schedule 20.06.2010

Если я хорошо понимаю, вы хотите иметь абстрактный «Элемент» и унаследовать «Вектор» от «Элемента». В этом случае вам следует удалить конструктор «Element» и объявить «плюс» и «минус» чисто виртуальными, добавив «= 0» в конце объявления. Однако ваш деструктор в порядке.

Это все, о чем идет речь об ошибке: поскольку вы объявили конструктор и некоторые методы в Element и в конечном итоге их вызываете, компоновщик ищет их.

У меня такое ощущение, что вы хотите, чтобы ваш класс Vector реализовал «плюс» и «минус» на векторе, а не на абстрактном элементе. Таким образом, вам не понадобится статическое приведение. Вы также избежите мучительного мира с огромными рисками, которые могут возникнуть из-за ваших возвращаемых типов.

person small_duck    schedule 20.06.2010
comment
Да, я поиграюсь с этим - я только начинаю разбираться в наследовании и не совсем уверен, что мне нужно статическое приведение. Я буду пробовать разные способы заставить его работать. - person Nick Sweet; 20.06.2010

Это действительно не имеет ничего общего с Vector. Вы объявляете такие методы, как virtual Element& plus(const Element&) и Element::Element() в Element.h, но вы должны определять их где-нибудь, предположительно в Element.cc. Если вы это сделали и по-прежнему получаете эту ошибку, это почти наверняка означает, что вы не связываете Element.o со своим исполняемым файлом, поэтому компоновщик просто не знает, что вставлять, когда Vector (или что-то еще ) вызывает эти методы.

person Beta    schedule 20.06.2010
comment
Потрясающе - я не знал, что мне действительно нужно определять функции, я думал, что смогу обойтись простым объявлением их. Чудесно! - person Nick Sweet; 20.06.2010