我如何知道哪个函数会被调用?
今天,我发现了以下令人不安的暧昧情况在我们的代码库:我如何知道哪个函数会被调用?
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_Container
,Get_A_Container
等以消除歧义。 C++使用什么规则来确定它应该调用哪个版本的函数?我想从本来应该被调用的“已知状态”开始,然后找出那里的错误。
例如,如果我有一个指向Base的指针并调用Get_Container,我认为它只会调用该函数的基本版本。如果我有指向A的指针呢?那么指向B的指针呢?那堆上的A或B怎么样?
谢谢。
这取决于你如何调用函数。如果您通过A *
,A &
或A
拨打电话,则您将拨打A::Get_Container()
。如果您通过Base *
,Base &
(即使他们指向/参考A
)拨打电话,则您将拨打Base::Get_Container()
。
只要不存在虚拟继承,这很容易。如果您直接使用对象,则会调用该对象的方法;如果您正在使用指针或引用,则它是确定方法的指针或引用的类型,并且指向的对象的类型无关紧要。
首先根据对象的静态类型查找方法。如果它是非虚拟的,那么你就完成了:这就是所谓的方法。动态类型是虚拟方法,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方法是可访问的,否则那些将是编译错误。
这里需要注意几点:
名称查找发生在单个作用域中;例如。在静态类型为'B'的对象上调用该方法时,编译器会认为'B'的接口确定是否存在有效的匹配。如果没有,它只会看基地的接口来找到一个匹配。这就是为什么从编译器的角度来看,没有任何不明之处,它可以解决这个问题。如果你的真实代码有重载等,这可能是一个问题。其次,经常忘记'受保护的'关键字适用于类而不是对象级。例如:
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();
}
};
如果您已经在基类中使用`= 0;`来编写它,它将不会编译。 `= 0`只能用于纯虚拟方法。 – wheaties 2011-01-27 23:16:48