C++中的虚函数层次结构
Posted
技术标签:
【中文标题】C++中的虚函数层次结构【英文标题】:virtual function hierarchy in c++ 【发布时间】:2015-02-03 19:39:53 【问题描述】:我对 C++ 中的虚函数主题有点困惑。 有没有总结所有可能情况的流程图?
例如:
class A
public:
virtual void f(const int i) cout << "A::f" << endl;
;
class B : public A
public:
// Hide A's f with new implementations
void f() cout << "B::f" << endl;
;
class C : public B
public:
void f() cout << "C::f" << endl;
;
class D : public B public:
void f(const int i) cout << "D::f" << endl;
;
void main()
D d;
C c;
B* pb = &c;
pb->f();
A* pa = &d;
A* paa = &c;
pa->f(1);
paa->f(1); //in here C::f would be invoked?
在这种情况下,B
隐藏了A::f
,并且C
具有对具有相同签名的B::f
的覆盖。
pb->f()
会调用C::f
吗?
pa->f(1)
会调用A::f
吗?
我要求它知道B::f
是否仍被认为是虚拟的,因此它的派生类可以覆盖它,尽管它隐藏了A::f
。
如果 C::f 默认被认为是虚拟的?
【问题讨论】:
“如果您提供virtual
关键字,pb->f()
会调用 C::f
吗?” No. 和 yes。
你的意思是一旦你隐藏了基础虚拟函数,隐藏函数默认不是虚拟的?
Virtual function calling using dereference object 的可能副本
@Day_Dreamer 您可能还想在这里阅读:***.com/questions/18198314/override-keyword-in-c
【参考方案1】:
A::f
和B::f
是两个不同的函数,尽管它们具有相同的名称;因为 B::f
没有被声明为 virtual
只有 A::f
是虚拟的 - 并且没有人覆盖它。
pb->f()
使用指针的静态类型B*
来判断调用哪个函数;那将是B::f
。
【讨论】:
【参考方案2】:
pb->f()
会调用C::f
吗?
不,不会的。
我要求它知道
B::f
是否仍被视为virtual
,因此它的派生类可以覆盖它,尽管它隐藏了A::f
。
B::f()
不是virtual
成员函数。
要使B::f()
成为虚拟成员函数,您必须使用:
class B : public A
public:
// Hide A's f with new implementations
virtual void f() cout << "B::f" << endl;
;
更新
您用以下附加问题更新了您的帖子:
pa->f(1)
会调用A::f
吗?
是的,会的。看透pa
,既不存在B::f()
也不存在C::f()
,只存在A::f(int)
。
【讨论】:
如果我用相同的签名声明 B::f 它将默认是虚拟的,即使没有明确的“虚拟”。所以你暗示当 B::f 隐藏具有不同签名的 A::f 时默认的“虚拟”被删除? @Day_Dreamer,部分正确。默认情况下,函数不是虚拟的。由于B::f()
与A::f(int)
无关,所以默认不是虚拟的。因此,删除“虚拟”不是正确的思考方式。 “虚拟”不是一开始就存在的。
@Day_Dreamer:没错,一个函数只有在重写虚函数时才是隐式虚函数。【参考方案3】:
是否有总结所有可能情况的流程图?
总的来说,您需要了解 C++ 中的整套名称查找规则,不幸的是,这非常复杂。
假设您只想知道什么覆盖了什么,您可以在标准的几段中找到所有详细信息。
如果在类
Base
和类Derived
中声明了一个虚成员函数vf
,则直接或间接派生 从Base
,声明了一个与Base::vf
具有相同名称、参数类型列表(8.3.5)、cv-qualification和ref-qualifier(或没有相同)的成员函数vf,然后Derived::vf
也是虚拟的(无论是否 如此声明)并且它覆盖Base::vf
。
...
即使不继承析构函数,派生类中的析构函数也会覆盖基类析构函数 声明为虚拟的;见 12.4 和 12.5。
...
重写函数的返回类型应与被重写函数的返回类型相同 函数或与函数的类协变。如果函数
都是指向类的指针,都是指向类的左值引用,或者都是指向类的右值引用 课程D::f
覆盖函数B::f
,则 如果满足以下条件,则函数的返回类型是协变的:B::f
返回类型中的类与D::f
返回类型中的类相同,或者是D::f
返回类型中类的明确且可访问的直接或间接基类 指针或引用都具有相同的 cv 限定和D::f
返回类型中的类类型 与B::f
的返回类型中的类类型具有相同或更少的cv-qualification。
因为B::f
没有与A::f
相同的参数类型,所以B::f
不会覆盖A::f
,出于同样的原因,C::f
不会覆盖A::f
。由于B::f
未声明virtual
并且 它不会覆盖A::f
,B::f
不是虚拟的。 C::f
不会覆盖 B::f
,因为 B::f
不是虚拟的。
由于B::f
不是虚拟的,pb->f()
总是调用B::f
,而不是派生类中任何名为f
的函数。
【讨论】:
【参考方案4】:B::f
确实 not 覆盖 A::f
,因为它们没有相同的参数类型列表,因此它也不是虚拟的,[class.virtual]/p2:
如果在类
Base
和类Derived
中声明了一个虚成员函数vf
,直接或间接派生自Base
,则一个同名的成员函数vf
, parameter-type-list (8.3.5)、cv-qualification 和 ref-qualifier(或不存在相同)作为Base::vf
声明,则Derived::vf
也是虚拟的(无论是否如此声明)并且它覆盖Base::vf
。
因此,无论派生类方法是否具有virtual
说明符,只要它匹配基类方法的某些属性,它就可以是隐式虚拟的。在这种情况下B::f
不是虚拟的,因此pb->f()
使用指针的静态类型B*
,并调用B::f
而不是C::f
。
【讨论】:
以上是关于C++中的虚函数层次结构的主要内容,如果未能解决你的问题,请参考以下文章