6

请考虑以下代码:

class Abase{};  
class A1:public Abase{};  
class A2:public A1{};  
//etc  

class Bbase{  
public:  
    virtual void f(Abase* a);  
    virtual void f(A1* a);  
    virtual void f(A2* a);  
};

class B1:public Bbase{  
public:
    void f(A1* a);  
};

class B2:public Bbase{  
public:
    void f(A2* a);
};  

int main(){  
    A1* a1=new A1();  
    A2* a2=new A2();  
    Bbase* b1=new B1();  
    Bbase* b2=new B2();  
    b1->f(a1); // calls B1::f(A1*), ok  
    b2->f(a2); // calls B2::f(A2*), ok  
    b2->f(a1); // calls Bbase::f(A1*), ok  
    b1->f(a2); // calls Bbase::f(A2*), no- want B1::f(A1*)! 
}  

我很想知道为什么 C++ 选择通过this将对象的指针向上转换到基类来解决最后一行的函数调用,而不是向上转换f()? 有什么办法可以得到我想要的行为?

4

5 回答 5

10

f通过查看参数的编译时类型来选择调用哪个版本。此名称解析不考虑运行时类型。由于b1is 的类型Bbase*,所有Bbase的成员都被考虑;接一个A2*是最好的匹配,所以这就是被调用的那个。

于 2010-06-23T15:59:41.687 回答
2

“...选择通过将对象的 this 指针向上转换到基类来解决最后一行的函数调用...”。你在说什么?在您的所有调用中,对象指针类型是Bbase *以及调用解析为属于其中一个Bbase或其后代的函数。编译器从不进行任何向上转换以解决您的调用。事实上,前两个调用需要向下转换才能调用正确的覆盖器,因为覆盖器属于位于层次结构中更下方的类。至于最后两个调用 - 它们Bbase通过类型指针分派到类中Bbase *。类型完全匹配,不进行任何类型的转换。

至于重载决议……重载决议是一个编译时过程,它基于参数的静态类型和可能转换的等级。你提供了一个A2 *类型的参数。f(A2 *)候选人完全符合你的论点。f(A1 *)候选人需要从A2 *到的额外转换A1 *。完全匹配的候选人被认为是更好的候选人,因此它赢得了重载决议。简单的。

于 2010-06-23T16:30:51.163 回答
1
b1->f(static_cast<A1*>(a2));

这应该强制编译器使用带有 A1 类型参数的重载方法。

于 2010-06-23T15:43:15.693 回答
0

这叫隐藏名字。您在一个派生类中声明的每一个 f 都会影响其任何基类中所有可能的 f。

使用对基类的强制转换来获得所需的行为。

当你覆盖一个虚函数时,你不会覆盖同名的重载函数。它们是不同的功能(并且在 vtable 中有不同的条目)。

于 2010-06-23T15:45:43.850 回答
0

您在 Bbase 中的 Abase 和 A2 重载隐藏在 B1 中。也许你可以像这样解决这个问题:

class Bbase{  
public:
    inline void f(Abase* a) { f_(a); }
    inline void f(A1* a) { f_(a); } 
    inline void f(A2* a) { f_(a); } 
protected:
    virtual void f_(Abase* a);  
    virtual void f_(A1* a);  
    virtual void f_(A2* a);  
};

class B1:public Bbase{  
protected:
    void f_(A1* a);  
};

class B2:public Bbase{  
protected:
    void f_(A2* a);
}; 

或使用 Bbase 中的模板:

class Bbase{  
public:
    template<class myA>
    inline void f(myA* a) { f_(a); }
protected:
    virtual void f_(Abase* a);  
    virtual void f_(A1* a);  
    virtual void f_(A2* a);  
};
于 2010-06-23T16:42:07.297 回答