我怎么知道将调用哪个函数?

时间:2011-01-27 23:09:07

标签: c++ class ambiguity

今天我在代码库中发现了以下令人不安的模糊情况:

class Base {
public:
    virtual void Irrelevant_Function(void) = 0;

protected:
    C_Container *   Get_Container(void);
};

class A : public Base, public Not_Important {
public:
    inline C_Container *    Get_Container(void);
};

class B : public Base, protected SomethingElse {
public:
    C_Container *   Get_Container(void);
};

许多事情都在调用Get_Container方法,但并不总是调用正确的方法 - 注意这些函数都不是虚拟的。

我需要重命名方法Get_Base_ContainerGet_A_Container等,以消除歧义。 C ++使用什么规则来确定它应该调用哪个版本的函数?我想从应该调用的“已知状态”开始,然后从中找出错误。

例如,如果我有一个指向Base的指针并调用Get_Container,我认为它只会调用该函数的Base版本。如果我有指向A的指针怎么办?指向B的指针怎么样?堆上的A或B怎么样?

感谢。

4 个答案:

答案 0 :(得分:5)

这取决于你如何调用该函数。如果您通过A *A &A来电话,那么您将拨打A::Get_Container()。如果您通过Base *拨打Base &(即使他们指向/引用A),您也会拨打Base::Get_Container()

答案 1 :(得分:3)

只要没有虚拟继承,就很容易了。如果你直接使用一个对象,它就是被调用的对象的方法;如果您正在使用指针或引用,则它是确定方法的指针或引用的类型,并且指向的对象的类型无关紧要。

答案 2 :(得分:1)

首先根据对象的静态类型查找方法。如果它是非虚拟的,那么你就完成了:那就是被调用的方法。动态类型是virtual methods,dynamic_cast和typeid使用的类型,是对象的“实际”类型。静态类型是静态类型系统使用的。

A a;                       // Static type and dynamic type are identical.
Base &a_base = a;          // Static type is Base; dynamic type is A.

a.Get_Contaienr();         // Calls A::Get_Container.
a_base.Get_Container();    // Calls Base::Get_Container.

B *pb = new B();           // Static type and dynamic type of *pb (the pointed-to
                           // object) are identical.
Base *pb_base = pb;        // Static type is Base; dynamic type is B.

pb->Get_Container();       // Calls B::Get_Container.
pb_base->Get_Container();  // Calls Base::Get_Container.

我上面假设可以访问受保护的Base :: Get_Container方法,否则会出现编译错误。

答案 3 :(得分:1)

这里还要注意几点:

名称查找发生在单个范围内;例如。在对静态类型为“B”的对象上调用方法时,编译器会将“B”的接口视为确定是否存在有效匹配。如果没有,它只会查看Base的接口以找到匹配项。这就是为什么从编译器的角度来看,没有歧义,它可以解决调用。如果您的真实代码有重载等,这可能是一个问题。

其次,经常会忘记'protected'关键字适用于类而非对象级别。例如:

class Base {
protected:
    C_Container *   Get_Container(void);
};

class B : public Base{
public:
    C_Container *   Get_Container(void)
    {
        B b;
        // Call the 'protected' base class method on another object.
        return b.Base::Get_Container();
    }
};