指向函数和派生类的指针

时间:2011-10-14 18:40:59

标签: c++ function-pointers derived-class

我遇到了g ++的问题以及模板如何与函数指针交互。请考虑以下模板声明。

template <class T,class B> class TestTemplate {

  private:
    T* context;

  public:
    TestTemplate(T* usingClass);

    B* testfcnOK(B* arg);
    B* testfcnBAD(B* (T::*fcn)(void));
};

template <class T,class B> TestTemplate<T,B>::TestTemplate(T* usingClass) {
  context = usingClass;
}

template <class T,class B> B* TestTemplate<T,B>::testfcnOK(B* arg) {
    return arg;
}

template <class T,class B> B* TestTemplate<T,B>::testfcnBAD(B* (T::*fcn)(void)) {
    return (context->*fcn)();
}

将T视为一个包含各种返回B类对象的函数的类。上面关注的方法是testfcnBAD(),因为它会导致问题。这是使用此模板的代码。

class Base { };
class Derived : public Base { };

class Tester {

  public:
   TestTemplate<Tester,Base> *templateClass;

   Base* returnBase() { return new Base(); }
   Base* returnDerivedOK() { return new Derived(); }
   Derived* returnDerivedBAD() { return new Derived(); }

   void runTest()
     {
       templateClass = new TestTemplate<Tester,Base>(this);

       // These work.
       Base* baseResult = templateClass->testfcnOK(new Base());
       baseResult = templateClass->testfcnOK(new Derived());
       baseResult = templateClass->testfcnBAD(&Tester::returnBase);
       Derived* derivedResult = (Derived*) templateClass->testfcnBAD(&Tester::returnDerivedOK);

       // This does not work.
       derivedResult = (Derived*) templateClass->testfcnBAD(&Tester::returnDerivedBAD);
     }
};

当给出runTest()的最后一行时,g ++(4.5.2)扼流圈。问题似乎是testfcnBAD()传递一个指向函数的指针,该函数返回Derived的实例,而TestTemplate声明testfcnBAD()以获取指向返回Base对象的函数的指针。看起来这个代码应该没问题,因为Derived对象一个Base对象,但是Derived是Base的一个子类的事实可能会在某个地方丢失。

我在这里遗漏了什么,是否有解决方法?

2 个答案:

答案 0 :(得分:1)

我不是C ++标准的专家,但据我所知,协变返回类型仅在覆盖函数时适用。您不能将covariant返回类型与函数指针一起使用。我会建议像:

template <class T,class B> class TestTemplate {

  private:
    T* context;

  public:
    TestTemplate(T* usingClass);

    B* testfcnOK(B* arg);
    template<typename D> B* testfcnBAD(D* (T::*fcn)(void));
};

答案 1 :(得分:0)

根据您的代码,如果您可以将Derived *(Derived:: *)()转换为Base *(Base:: *)(),则会违反类型安全:

Derived *(Derived:: *derived_method)()= &Derived::returnDerivedBAD;
Base *(Base:: *base_method)()= derived_method;
Base b;
(b.*base_method)(); // would compile, but invalid at runtime! Oops!

所以你不能安全地“解决它”。即使您更改了匹配的返回类型,它仍然会违反类型安全。