我有一个关于C ++的理论问题。这是我大学期末考试的一部分,我想知道为什么调用类f
的方法B
,而它应该由基类A
派生。既然不是虚拟的,不应该调用A :: f()吗?
#include <iostream.h>
#include <stdlib.h>
class A{
public:int f(int x){
cout<< x << " ";
}
};
class B:public A{
public:int f(int y){
A::f(y+1);
}
};
void g(A a, B b) {
a.f(3);
b.f(3);
}
int main()
{
B p;
B q;
g(p,q);
system("PAUSE");
return 0;
}
// result is 3 4
答案 0 :(得分:2)
b
中g()
的静态类型是B
,因此这里不需要虚拟 - 编译器可以知道[在编译时]你要调用{{1这正是他正在做的事情。
在这里,课程B::f()
重新定义了B
的{{1}}并隐藏了它,因此从静态类型为{{1}的变量调用A
}导致调用f()
请注意,f()
关键字允许您使用覆盖方法,其中静态类型是父类型。
答案 1 :(得分:2)
方法g
有两个参数,类型为A
和B
。由于这些不是指针或引用类型,因此动态绑定不适用。编译器在编译时知道对象的实际类型,并进行静态方法调用。
virtual
方法仅适用于指针或引用!
答案 2 :(得分:1)
类int f(int)
中的函数B
“隐藏”其基类中具有相同名称和签名的函数。
因此,当您致电b.f(3);
并且变量b
的类型为B
时,您正在调用B::f
。
只有在{em>变量 b.f(3)
的类型为B::f
的情况下,b
才能调用A&
,才需要虚拟函数,但它引用的对象具有运行时类型B
。在这种情况下,如果B::f
是虚拟的,则调用的函数将为A::f
,如果为非虚拟,则调用A::f
。
虚函数调用将对象的运行时类型考虑在内,即使它们是通过指针或对基类的引用使用的。但B b; b.f(3)
是对B::f
的调用,无论A::f
是否存在,都不管它是虚拟的还是非虚拟的。
答案 3 :(得分:0)
“非科学”解释:
函数g
将 获取a
视为A
的实例p
的副本作为对象类型为A
(请参阅下面的评论),并在f
内执行A
。 b
被视为B
的实例,其中方法B.f
会覆盖A.f
,因此当b
被“查看”为B
的实例时1}}我们执行b.f
,方法B.f
将被执行,因为A.f
不可见
如果您想使用A.f
致电b.f
,则必须将b
投放到A
:((A)b).f()
。
答案 4 :(得分:0)
这里发生了两件事:
f()
函数不是覆盖,因为它不是虚拟的,实际上您不应该这样做。您可以通过使函数g通过引用获取其第一个参数来克服切片。如果给A一个受保护的拷贝构造函数也会阻止它,尽管那时你将无法复制A的真实实例。
在这种情况下,即使参考A,函数g也总是会调用A::f()
,因为没有多态性。要调用它,您需要将A::f()
声明为虚拟。