Не могу вызвать метод базового класса, хотя у меня есть указатель на него (Decorator)? - PullRequest
0 голосов
/ 15 мая 2009

У меня есть шаблонный класс, который я разделил с указателем на него (шаблон Decorator). Я добавил getBase() вызов, чтобы вернуть указатель на базовый класс для любых дальнейших подклассов. Однако, когда я использую этот getBase() и вызываю метод только базовых классов, я получаю ошибку компоновщика, что он не может найти символ для этого метода в промежуточном (Decorator) классе?

Как это:

template <typename T> class B {    
  public:
    typedef std::auto_ptr<T> MYFUN( 
      std::istream&, const std::string&, const std::string& );

  public:
    B<T>( MYFUN* p );
    auto_ptr<T> fun( istream& );

  private:
    MYFUN *fptr;
};

template <typename T>
class D : public class B<T>
{
  D( typename B<T>::MYFUN *fPtr, B<T> *providedBase );
  //Looks like B
  B* getBase() { return base_ ; }
  private:
    B* base_;
};

template <typename T>
class Dagain : public class D<T>
{
  //Looks like D
  auto_ptr<T> fun( istream& );
};

auto_ptr<T>
Dagain::fun( istream& is )
{
  this->getBase()->fun( is );
}

Обратите внимание, что в D<T> нет определения для fun( istream& ). Цель состоит в том, чтобы клиент использовал указатель на базу для вызова B<T>::fun( istream& )

Когда клиент создает объект Dagain, компоновщик говорит (в основном):

Client.o:<br> (.data.rel.ro. --stuff--<br> [vtable for D<T>]:<br> undefined reference to<br> 'D<T>::fun( basic_istream<char, char_traits<char> >&)'

Но я не называю D определением fun(istream&) ... его даже нет! Я использую указатель непосредственно на базовый класс ... Когда я добавляю определение для D<T>::fun(istream&), все работает, но я не понимаю, почему?

Ответы [ 4 ]

1 голос
/ 27 мая 2010

Вы забыли указать параметр шаблона в определении шаблона. Кроме того, у вас было еще несколько ошибок. Вот рабочий код:

template <typename T> class B {
  public:
    typedef std::auto_ptr<T> MYFUN(
      std::istream&, const std::string&, const std::string& );

  public:
    B<T>( MYFUN* p );
    auto_ptr<T> fun( istream& );

  private:
    MYFUN *fptr;
};

template <typename T>
class D : public B<T>
{
  D( typename B<T>::MYFUN *fPtr, B<T> *providedBase );
  //Looks like B
  B<T>* getBase() { return base_ ; }
  private:
    B<T>* base_;
};

template <typename T>
class Dagain : public D<T>
{
  //Looks like D
  auto_ptr<T> fun( istream& );
};

template <typename T>
auto_ptr<T>
Dagain<T>::fun( istream& is )
{
  this->getBase()->fun( is );
}
0 голосов
/ 15 мая 2009

Мне кажется, что ваш getBase возвращает неправильный тип. Должен возвращаться правильный тип базового класса:

template <typename T>
class D : public class B<T>
{
  ...
  //Looks like B
  B<T>* getBase() { return base_ ; }
  private:
    B<T>* base_;
};
0 голосов
/ 15 мая 2009

То, что вы называете «базой», на самом деле не так - D имеет реальную базу B (из-за наследования) и фальшивую через этот указатель. Относительно того, почему компилятор жалуется на vtable, когда у вас вообще нет виртуалов, это странно - вы уверены, что у вас где-то нет виртуальной машины?

0 голосов
/ 15 мая 2009

Я не эксперт по C ++ и не уверен, имеет ли это какое-либо отношение к шаблонам, но если мы игнорируем шаблоны, я думаю, что часть вашей проблемы может заключаться в том, что fun () в B не является виртуальной.

Когда вы вызываете getBase (), вы получаете статический тип B *, а затем, когда вызываете fun () для него, вы получаете версию из B, а не версию в DAgain. Я думаю, что компоновщик будет жаловаться на то, что вы не определили версию для B (и, следовательно, для D). Тот факт, что fun () переопределяется в DAgain, будет недостаточным, поскольку привязка является статической.

Другой вариант заключается в том, что возвращение B *, а не B * может быть проблемой, но я не играл с C ++ достаточно недавно.

...