指向函数和派生类的指针

发布于 2024-12-09 15:48:07 字数 1805 浏览 0 评论 0原文

我对 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 的子类这一事实可能会在某个地方丢失。

我在这里遗漏了什么吗?有解决方法吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

农村范ル 2024-12-16 15:48:07

我不是 C++ 标准方面的专家,但据我所知,协变返回类型仅在重写函数时适用。不能将协变返回类型与函数指针一起使用。我会提出类似的建议:

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

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));
};
蓝天 2024-12-16 15:48:07

根据您的代码,如果您可以将 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!

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文