简体   繁体   English

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

[英]How do I know which function will be called?

Today I found the following disturbingly ambiguous situation in our code base: 今天,我在代码库中发现了以下令人不安的模棱两可的情况:

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

Many things were calling the Get_Container method, but not always calling the correct one - note that none of these functions were virtual. 很多事情都在调用Get_Container方法,但并不总是调用正确的方法-请注意,这些函数都不是虚拟的。

I need to rename the methods Get_Base_Container , Get_A_Container , etc to remove the ambiguity. 我需要重命名方法Get_Base_ContainerGet_A_Container等,以消除歧义。 What rules does C++ use to determine which version of a function it should call? C ++使用什么规则来确定应调用的函数版本? I'd like to start from the "known state" of what should have been getting called, and then figure out the bugs from there. 我想从应该被调用的“已知状态”开始,然后从那里找出错误。

For example, if I have a pointer to a Base and call Get_Container, I assume it would just call the Base version of the function. 例如,如果我有一个指向Base的指针并调用Get_Container,则假定它只会调用该函数的Base版本。 What if I have a pointer to an A? 如果我有一个指向A的指针怎么办? What about a pointer to a B? 指向B的指针呢? What about an A or B on the heap? 堆上的A或B呢?

Thanks. 谢谢。

It depends how you're calling the function. 这取决于您如何调用该函数。 If you're calling through an A * , an A & or an A , then you'll be calling A::Get_Container() . 如果通过A *A &A进行调用,则将调用A::Get_Container() If you're calling through a Base * , a Base & (even if they point to/reference an A ), then you'll be calling Base::Get_Container() . 如果您通过Base *Base & (即使它们指向/引用A )进行调用,那么您将在调用Base::Get_Container()

As long as there's no virtual inheritance going on, it's quite easy. 只要不进行虚拟继承,就很容易。 If you're working directly with an object, it's the object's method that gets called; 如果直接使用对象,则调用该对象的方法。 if you're working with a pointer or reference, it's the type of the pointer or reference that determines the method, and the type of the object pointed to doesn't matter. 如果您使用的是指针或引用,则由指针或引用的类型决定方法,而指向的对象的类型则无关紧要。

A method is first looked up according to the object's static type. 首先根据对象的静态类型查找方法 If it is non-virtual there, you're done: that's the method that's called. 如果那里不是虚拟的,那您就完成了:那就是调用的方法。 The dynamic type is what virtual methods, dynamic_cast, and typeid use, and is the "actual" type of the object. 动态类型是虚拟方法,dynamic_cast和typeid使用的类型,并且是对象的“实际”类型。 The static type is what the static type system works with. 静态类型是静态类型系统的工作方式。

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.

I've assumed above that the protected Base::Get_Container method is accessible, otherwise those will be compile errors. 上面我假设受保护的Base :: Get_Container方法是可访问的,否则这些将是编译错误。

A couple of additional points to note here: 在此需要注意的其他几点:

Name lookup occurs in a single scope; 名称查找在单个作用域中进行; Eg When calling the method on an object with static type 'B', the compiler considers the interface of 'B' to determine whether or not there is a valid match. 例如,当在静态类型为'B'的对象上调用该方法时,编译器将考虑接口'B'以确定是否存在有效的匹配项。 If there is not, it only then looks at the interface of Base to find a match. 如果不存在,则仅查看Base的接口以找到匹配项。 This is why that from the compiler's view, there is no ambiguity and it can resolve the call. 这就是为什么从编译器的角度来看,没有歧义并且可以解决调用的原因。 If your real code has overloading etc. this may be an issue. 如果您的真实代码有重载等,则可能是一个问题。

Secondly, it is often forgotten that the 'protected' keyword applies at class and not object level. 其次,通常会忘记“ protected”关键字在类而非对象级别适用。 So for example: 因此,例如:

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();
    }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM