指向函数和派生类的指针
我对 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不是 C++ 标准方面的专家,但据我所知,协变返回类型仅在重写函数时适用。不能将协变返回类型与函数指针一起使用。我会提出类似的建议:
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:
根据您的代码,如果您可以将
Derived *(Derived:: *)()
转换为Base *(Base:: *)()
,则会违反类型安全性:所以你无法安全地“解决它”。即使您更改返回类型以匹配,它仍然会违反类型安全。
Given your code, if you could convert a
Derived *(Derived:: *)()
toBase *(Base:: *)()
, you would violate type safety:So you can't "work around it" safely. Even if you changed the return type to match, it would still violate type safety.