即使我有一个指针(Decorator),也无法调用基类方法?

时间:2009-05-14 21:03:03

标签: c++ templates decorator

我有一个模板类,我已经用它的指针(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 );
}

请注意,fun( istream& )中没有D<T>的定义。目的是让客户端使用指向基址的指针来调用B<T>::fun( istream& )

当客户端构造Dagain对象时,链接器说(基本上):

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

但是,我并没有打电话给 D fun(istream&)的定义......它甚至都没有!我正在使用指针直接指向基类...当我为D<T>::fun(istream&)添加一个定义工作时,但我不明白为什么?

4 个答案:

答案 0 :(得分:1)

您忘记在模板定义中指定模板参数。此外,您还有一些错误。这是工作代码:

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 );
}

答案 1 :(得分:0)

我不是C ++专家,也不确定这是否与模板有关,但如果我们忽略模板,我认为你的问题的一部分可能就是B中的fun()不是虚拟的。

当你调用getBase()时,你得到一个静态类型的B *,然后当你调用fun()时,你得到的是B版本而不是DAgain版本。我认为链接器会抱怨你没有为B定义版本(因此也没有为D定义)。在DAgain中覆盖fun()这一事实是不够的,因为绑定是静态的。

另一个选择是返回B *而不是B *可能是问题,但我最近还没有充分利用C ++。

答案 2 :(得分:0)

在我看来,getBase正在返回错误的类型。它应该返回正确类型的基类:

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

答案 3 :(得分:0)

你所谓的“基础”实际上不是--D有一个真正的B基(由于继承)和一个假的通过该指针。至于为什么当你看起来根本没有虚拟机时,编译器抱怨vtable,这很奇怪 - 你确定你没有虚拟的地方吗?