我在父类中有一个模板方法,它应该从基类调用另一个方法。如果方法在基类中明确定义,它可以工作,但如果方法是继承的,它就不起作用。我无法弄清楚这段代码究竟有什么问题(虽然我知道这有点奇怪:)
class A
{
protected:
virtual void someMethod()
{
}
template <class TBaseClass>
void templateMethod()
{
TBaseClass::someMethod();
}
};
class B : public A
{
};
class C : public B
{
protected:
virtual void someMethod()
{
templateMethod<A>(); // this works
templateMethod<B>(); // this doesn't
}
};
这最终导致编译器错误:
错误C2352:&#39; A :: someMethod&#39; :非静态成员函数的非法调用
究竟出了什么问题?我不是在寻找变通方法,这很容易。我想知道为什么这不正确。
答案 0 :(得分:1)
在template <TBaseClass> void A::templateMethod()
this
中,调用者A *
的类型为B::someMethod
。因此,当您尝试在其上调用B
时,编译器不会将其识别为对象方法调用,因为B::someMethod
不是基类,但它仍然可以是静态方法调用,所以编译器会尝试这一点,找到通过A
继承的A
并抱怨它不是静态的。 this
是B
的基类这一事实并不重要;仅{{1}}不是。
答案 1 :(得分:0)
我认为它不起作用,因为你试图调用静态方法。 静态方法可以继承,但不能是虚拟的。 这就是为什么A :: someMethod会起作用而B :: someMethod不会起作用。
答案 2 :(得分:0)
问题是A类不会自动被授予对B类的访问权限。类中的方法不知道A的当前实例实际上是B类。
要执行您正在尝试的操作,您需要将A强制转换为目标类型:
template <class TBaseClass>
void templateMethod()
{
static_cast<TBaseClass*>(this)->someMethod();
}
如果您正在调用的A的特定实例确实是B(在您给出的示例中),这将起作用。这里没有进行类型检查以确保它是。如果传递的类不在继承层次结构中,那么您将处于未定义行为的工作中。
那就是说,你的例子将“someMethod()”视为虚拟。如果你正在做我刚才做的事情,那么将该方法设为虚拟可能没有意义,因为你明确地说明了你想要的实例。如果你把它保留为虚拟,那么直接在A中调用someMethod()将获得最多派生的实例。