2013-07-22 3 views
4

Доброго утра,Автоматического опущенными указателя на производный объект

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

Вот моя проблема: вызвать метод производного класса из указателя на базовый класс, я не могу использовать виртуальные функции, потому что функции шаблонов нельзя сделать виртуальными. Мне нужно сделать явный бросок, который является утомительным: как только создать числовой объект с новым, на самом деле, нужно сделать снимок для числа *, хотя известно, что объект является номером заранее.

Я решил эту проблему неловко: функция myset проверяет все поддерживаемые значения typeid для получения правильной динамической трансляции. Это длинная серия вложенных ifs, которые выполняют проверку типов.

Помимо утомительности функция работает только для вызова метода «set», а для вызова других методов должны быть определены аналогичные функции. Если бы я мог сделать автоматическое кастинг на тот объект, на который я указываю, все будет намного проще.

Недостатки этого подхода являются:

  1. код повторяется: если я определил другую функцию (например, Т получаем() {вернуться Val;}, я должен был бы еще одну функцию myget с полным набором гнездовых МФС!
  2. список поддерживаемых типов должны быть четко определены вложенности, если вызовы
  3. код может быть неэффективным

компилятор знает, что LST [0] (в коде ниже) указывает наumber объект, хотя lst является вектором объектов элемента, из которого выведены числа <>.

Есть ли способ автоматического понижения указателя, определенного как base *, указателю на объект, на самом деле направленный?

Если бы я был правильный понижающее приведение, то я мог бы определить тысячи методов числа <> класса и назвать их с propercasting функция -> (...) вызов

Вот код (он работает правильно , ядро ​​определение «ой»)

Спасибо заранее, Pietro М.

PS Я в основном заинтересован в стандартном подходе C++ без использования других библиотек, кроме STL, таких как Boost.

#include <iostream> 
#include <vector> 
#include <typeinfo> 

using namespace std; 

class element 
{ 
public: 
    virtual void print() = 0; // print is not templatized and works properly 
    //template <class T> virtual set(T v) = 0; // this would solve all my problems, if only it were legal. 
}; 

template <class T> 
class number : public element 
{ 
    T val; 
public: 
    void print() {cout << "number is " << val << endl;} 
    void set(T v) {val = v;} 
}; 

// That's the best I can do! 
template <class T> 
void myset(T v, element *ptr) 
{ 
    // There is a kink in the template: the compiler checks the T type by the value of v, that in this case is an integer: 
    // cout << "Type name for the template is: " << typeid(T).name() << endl; 
    // cout << "Type name for an integer is: " << typeid(int).name() << endl; 

    if (typeid(*ptr) == typeid(number<double>)) 
    { 
     ((number<double> *) ptr) -> set(7); 
     return; 
    } 
    else if (typeid(*ptr) == typeid(number<float>)) 
    { 
     ((number<float> *) ptr) -> set(7); 
     return; 
    } 
    // add other types... (tedious) 
    else 
    { 
     cout << "type not supported" << endl; 
    } 
} 

int main() 
{ 
    vector <element *> lst; // list of heterogeneous templatized objects 
    lst.push_back(new number<float>); 
    lst.push_back(new number<double>); 

    lst[0] -> print(); 

    //((number<float> *) lst[0]) -> set(7); it's correct but it requires I know the type when I call it (tedious) 

    myset(7, lst[0]); // may be inefficient, but it works (for the types which are explicitly supported) 

    // cast_to_what_the_pointer_actually_points_to <lst[0]> -> set(7); // that's what I'd like to do: a downcast function which checks the object type and returns the correct pointer would be able to call any class method... 

    lst[0] -> print(); 
} 
+0

Таким образом, типы не имеют общего интерфейса (ну, кроме 'print'). Почему вы пытаетесь рассматривать их как таковые? (Альтернативно, вы можете использовать язык с динамической типизацией вместо C++) –

+0

Я бы хотел, чтобы у них был общий интерфейс с использованием полиморфизма, но я не могу определить шаблон virtual void set (T) = 0; в базовом классе, потому что компилятор не хочет создавать виртуальные функции шаблона. Я не нашел способа определить виртуальную функцию внутри элемента, поэтому я надеялся, что смогу обойти это ограничение. – pietrom79

+1

Нет, это не похоже на то, что вы хотите. Вы не хотите, чтобы все подклассы имели функции для принятия * любых и всех типов * (это то, что будет означать виртуальная функция шаблона, и это также причина, по которой это запрещено). Первым шагом для решения этой проблемы является определение того, что вы хотите от этого. –

ответ

3

Вы почти у цели. Вы должны иметь шаблонный set метод, который вызывает частный виртуальный метод с typeid и void * указателя на аргумент, что позволяет переопределение решить, как справиться с этим:

class element 
{ 
    virtual void set_impl(const std::type_info &, const void *) = 0; 
public: 
    template <class T> void set(T v) { set_impl(typeid(v), &v); } 
}; 

И примером того, как написать set_impl :

template <class T> 
class number : public element 
{ 
    T val; 
    void set_impl(const std::type_info &ti, const void *pv) { 
     if (ti == typeid(T)) { 
      val = *static_cast<const T *>(pv); 
     } else { 
      throw std::invalid_argument("incorrect type to set()"); 
     } 
    } 
}; 

Это похоже на подход, принятый Boost.Any.

+0

Большое спасибо. Я пытался заставить его работать, но есть проблема. Если я вызову набор функций, компилятор будет вызывать тип шаблона из аргумента v, а не из производного объекта. Если я звоню lst [0] -> set (7); Параметр шаблона будет int, потому что '7' интерпретируется как таковой. Таким образом, компилятор вызовет метод с номером , который не является классом, указанным lst [0]. Я попытался решить проблему, вызвав set_impl с помощью typeid (* this), но затем v, сохраненный как целое число, интерпретировался как float, предоставляя бессмысленный результат. В любом случае, я довольно близко. Благодаря! – pietrom79

Смежные вопросы