重载的虚函数调用解析

时间:2010-06-23 15:38:53

标签: c++ overloading virtual-functions overload-resolution

请考虑以下代码:

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()的参数?有什么方法可以让我得到我想要的行为吗?

5 个答案:

答案 0 :(得分:10)

通过查看参数的编译时类型来选择要调用的f版本。此名称解析不考虑运行时类型。由于b1的类型为Bbase*,因此会考虑所有Bbase个成员;采用A2*的那个是最佳匹配,所以这是被调用的那个。

答案 1 :(得分:2)

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

关于重载解析...重载解析是一个编译时进程,它基于参数的静态类型和可能的转换等级。您提供了A2 *类型的参数。 f(A2 *)候选人与您的论据正好匹配f(A1 *)候选人需要从A2 *A1 *的额外转化。完全匹配的候选者被认为是更好的候选者,因此它赢得了重载决策。简单。

答案 2 :(得分:1)

b1->f(static_cast<A1*>(a2));

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

答案 3 :(得分:0)

它被称为名字隐藏。您在一个派生类中声明的每个f都会在其任何基类中隐藏每个可能的f。

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

覆盖虚函数时,不要覆盖具有相同名称的重载函数。它们是不同的功能(并且在vtable中具有不同的条目)。

答案 4 :(得分:0)

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