1

今天,我在我们的代码库中发现了以下令人不安的模棱两可的情况:

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

4 回答 4

5

这取决于您如何调用该函数。如果您通过 an A *、 anA &或 anA呼叫,那么您将呼叫A::Get_Container()。如果您通过 a Base *、 a调用Base &(即使它们指向/引用 an A),那么您将调用Base::Get_Container().

于 2011-01-27T23:13:54.757 回答
3

只要没有虚拟继承,就很容易。如果您直接使用对象,则调用的是对象的方法;如果您使用的是指针或引用,则指针或引用的类型决定了方法,而指向的对象的类型无关紧要。

于 2011-01-27T23:18:31.253 回答
1

首先根据对象的静态类型查找方法。 如果它在那里是非虚拟的,那么你就完成了:这就是被调用的方法。动态类型是虚方法、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 方法是可访问的,否则这些将是编译错误。

于 2011-01-27T23:23:29.600 回答
1

这里还有几点需要注意:

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

其次,经常忘记“受保护”关键字适用于类而不是对象级别。例如:

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();
    }
};
于 2011-01-28T00:33:35.240 回答