Как обрабатывать указатель Base * как производный указатель <T>*? - PullRequest
1 голос
/ 18 апреля 2010

Я хотел бы хранить указатели на класс Base в vector, но затем использовать их в качестве аргументов функции, где они действуют как определенный класс, см. Здесь:

#include <iostream>
#include <vector>

class Base {};

template<class T>
class Derived : public Base {};

void Foo(Derived<int>* d) {
  std::cerr << "Processing int" << std::endl;
}

void Foo(Derived<double>* d) {
  std::cerr << "Processing double" << std::endl;
}

int main() {
  std::vector<Base*> vec;
  vec.push_back(new Derived<int>());
  vec.push_back(new Derived<double>());
  Foo(vec[0]);
  Foo(vec[1]);
  delete vec[0];
  delete vec[1];
  return 0;
}

Это не компилируется:

error: call of overloaded 'Foo(Base*&)' is ambiguous

Можно ли заставить его работать? Мне нужно обрабатывать элементы вектора по-разному, в зависимости от типа int, double и т. Д.

Ответы [ 4 ]

5 голосов
/ 18 апреля 2010

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

Пример:

#include <iostream>
#include <vector>

class Base {
  public:
    virtual void Foo() {
      std::cerr << "Processing base" << std::endl;
    }
};

template<class T>
class Derived : public Base {};

template <>
class Derived <int> : public Base {
  public:
    void Foo() {
      std::cerr << "Processing int" << std::endl;
    }
};

template <>
class Derived <double> : public Base {
  public:
    void Foo() {
      std::cerr << "Processing double" << std::endl;
    }
};

int main() {
  std::vector<Base*> vec;
  vec.push_back(new Derived<int>());
  vec.push_back(new Derived<double>());
  vec[0]->Foo();
  vec[1]->Foo();
  delete vec[0];
  delete vec[1];
  return 0;
}
1 голос
/ 18 апреля 2010

Вы можете сделать это так:

#include <iostream>
#include <vector>

class Base {
public:
        virtual void DoFoo() = 0;
};

template<class T>
class Derived : public Base {
public:
  virtual void DoFoo() {
          Foo(this);
  }
};

void Foo(Derived<int>* d) {
  std::cerr << "Processing int" << std::endl;
}

void Foo(Derived<double>* d) {
  std::cerr << "Processing double" << std::endl;
}


int main()
{
  std::vector<Base*> vec;
  vec.push_back(new Derived<int>());
  vec.push_back(new Derived<double>());
  vec[0]->DoFoo();
  vec[1]->DoFoo();
  delete vec[0];
  delete vec[1];

  return 0;
}
1 голос
/ 18 апреля 2010

Конечно, это неоднозначно, как компилятор может определить, какой конкретный подкласс Base содержится в vec [0].

Вы можете устранить неоднозначность путем явного приведения:

Foo( (Derived<int>*) vec[0] )

или, что лучше, рассмотрите возможность использования динамического разрешения метода:

class Base {
    virtual void Foo() = 0;
};

template <class T>
class Derived: Base {
    void Foo() { /* .. doFoo<T>(...) .. */ }
};

template<class T> void doFoo() { /* .. general case .. */ }
template<> void doFoo<int>() { /* .. int case .. */}
template<> void doFoo<double>() { /* .. double case .. */}

и в своем коде просто позвоните

vec[0]->Foo()
1 голос
/ 18 апреля 2010

Когда вы вводите тип от Derived<int>* до Base*, вы теряете информацию о том, какой у вас производный класс, если вы не используете RTTI (идентификация типа RunTime).

Если вы включили RTTI, вы можете попытаться типизировать Base* пересылку к указателю производного типа, используя dynamic_cast<>():

void Foo(Base* base)
{
    Derived<int>* derivedInt = dynamic_cast<Derived<int>*>(base);
    if(derivedInt)
    {
        Foo(derivedInt);
        return;
    }
    Derived<double>* derivedDouble = dynamic_cast<Derived<double>*>(base);
    if(derivedDouble)
    {
        Foo(derivedDouble);
        return;
    }
    // Handle other cases here.
}

dynamic_cast возвращает NULL, если указатель не указывает на правильный тип.

В качестве альтернативы, если вы не хотите использовать RTTI и dynamic_cast, вам необходимо сохранить некоторые средства для определения того, какой подкласс хранится в вашем векторе (обычно значение enum хранится вместе с указателем, возможно, в pair, или с помощью метода в Base, который возвращает аналогичный enum) и использования reinterpret_cast<>() для типизации указателя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...