开发者

Pointers to functions and derived classes

开发者 https://www.devze.com 2023-04-13 07:13 出处:网络
I\'m having a problem with g++ and how templates interact with pointers to functions. Consider the following declaration of a template.

I'm having a problem with g++ and how templates interact with pointers to functions. Consider the following declaration of a template.

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

Think of T as a class which contains various functions which return objects of type B. The method to focus on above is testfcnBAD() since it causes the problem. Here's the code that uses this template.

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

When given the last line of runTest(), g++ (4.5.2) chokes. The problem seems to be that testfcnBAD() is passed a pointer to a function which returns an instance of Derived, while TestTemplate declares testfcnBAD() to take a pointer to a function which returns a Base object. It seems like this code should be OK because a Derived object is a Base object, but the fact that Derived is a sub-class of Base may be lost somewhere along the line.

Am I missing something here, and is there a work-around?


I'm no expert in the C++ Standard, but from what I can tell, covariant return types only apply when overriding a function. You cannot use covariant return types with a function pointer. I would propose something like:

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


Given your code, if you could convert a Derived *(Derived:: *)() to Base *(Base:: *)(), you would violate type safety:

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

So you can't "work around it" safely. Even if you changed the return type to match, it would still violate type safety.

0

精彩评论

暂无评论...
验证码 换一张
取 消