从您问题的标题来看,我认为您不完全了解函数何时被隐藏、重载和覆盖。
示例代码1:
struct Base
{
void foo()
{
}
};
struct Derive: public Base
{
void foo()
{
}
};
int main()
{
Derive d;
Base *pb=&d;
d.foo(); // Resolves to Derived::foo()
pb->foo(); // Resolves to Base::foo()
return 0;
}
为什么d.foo()
调用Derived::foo()
和pb->foo()
调用Base::foo()
?
该问题的答案在于编译器为解决这些函数绑定而采取的步骤。
给定一个 T 类型的对象和一个函数名f
,编译器查找在 中命名的f
函数T
。如果它只找到一个名为 的函数f
,则对函数的搜索将停止。如果它找到多个函数,它会尝试从 中找到的一组函数中进行重载解析T
。
如果它没有找到任何名为f
inT
且T
具有基类的函数,它会在 的基类中尝试上述逻辑T
。如果T
没有任何基类,编译器会报错。
来到示例代码的对象......
在处理函数调用d.foo()
时,编译器会查找foo
in Derived
。它在那里找到一个匹配项并停止。由于Derived::foo()
不是virtual
函数,因此绑定是在编译时完成的。在运行时,Derived::foo()
被调用。
在处理函数调用pb->foo()
时,编译器会查找foo
in Base
。它在那里找到一个匹配项并停止。由于Base::foo()
不是virtual
函数,因此绑定是在编译时完成的。在运行时,Base::foo()
被调用。
示例代码 2:
struct Base
{
void foo(int i)
{
}
};
struct Derive: public Base
{
void foo()
{
}
};
int main()
{
Derive d;
Base *pb=&d;
d.foo(); // Resolves to Derived::foo()
d.foo(10); // Compiler error.
pb->foo(10); // Resolves to Base::foo(int)
pb->foo(); // Compiler error.
return 0;
}
为什么编译器会在这里产生错误?
在处理函数调用d.foo(10)
时,编译器会查找foo
in Derived
。它在那里找到一个匹配项并停止。它尝试使用该函数,但该函数的签名与调用代码不匹配。因此,这是一个编译器错误。
在处理函数调用pb->foo()
时,编译器会查找foo
in Base
。它在那里找到一个匹配项并停止。它尝试使用该函数,但该函数的签名与调用代码不匹配。因此,这是一个编译器错误。
一旦编译器找到 a foo
inDerived
它就不会去搜索匹配foo
的 in Base
。
在这种情况下,你可以认为Derived::foo
是完全隐藏Base::foo
。
示例代码 3:
struct Base
{
void foo()
{
}
};
struct Derive: public Base
{
void foo()
{
}
void foo(int )
{
}
};
int main()
{
Derive d;
d.foo(); // Resolves to Derived::foo()
d.foo(10); // Resolves to Derived::foo(int)
Base *pb=&d;
pb->foo(); // Resolves to Base::foo()
pb->foo(10); // Compiler error.
return 0;
}
在处理函数调用d.foo()
时d.foo(10)
,编译器会查找foo
in Derived
。它在那里找到了几个匹配项并停止。然后它尝试重载决议。它能够找到两个版本的匹配项。由于Derived::foo()
s 都不是virtual
函数,因此绑定是在编译时完成的。
在处理函数调用bp->foo()
时bp->foo(10)
,编译器会查找foo
in Base
。它在那里找到了几个匹配项并停止。然后它尝试重载决议。它能够为第一个版本找到匹配项,但不能为第二个版本找到匹配项。它会为第二次调用生成错误。
这里Derived::foo
不仅隐藏Base::foo
,而且还有两个重载版本的Derived::foo
.
示例代码 4:
struct Base
{
virtual void foo()
{
}
void foo(int)
{
}
};
struct Derive: public Base
{
void foo()
{
}
void foo(int )
{
}
};
int main()
{
Derive d;
d.foo(); // Resolves to Derived::foo()
// But Derived:foo() gets called at run time.
d.foo(10); // Resolves to Derived::foo(int)
// But Derived:foo(int) gets called at run time.
Base *pb=&d;
pb->foo(); // Resolves to Base::foo()
// But Derived:foo() gets called at run time due to
// function overwritting.
pb->foo(10); // Resolves to Base::foo(10)
// Base:foo(int) gets called at run time.
return 0;
}
这包括函数隐藏、函数重载和函数覆盖。
Derived::foo
隐藏Base::foo
。
Derived::foo()
并且Derived::foo(int)
超载。
Base::foo()
并且Base::foo(int)
超载。
Base::foo()
被 覆盖Derived::foo()
。
我希望这能消除你的一些疑问。