C++ 中的虚函数层次结构
virtual function hierarchy in c++
我对 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 默认被视为虚拟?
A::f
和B::f
是两个不同的函数,即使它们具有相同的名称;由于B::f
没有被声明为virtual
所以只有A::f
是虚拟的 - 没有人覆盖它。
pb->f()
使用指针的静态类型(即B*
)来确定要调用的函数;这将是B::f
。
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)
存在。
是否有总结所有可能案例的流程图?
一般来说,您需要了解C++中的整套名称查找规则,不幸的是,这非常复杂。
假设您只想知道什么覆盖了什么,您可以在标准的几个段落中找到所有详细信息。
如果虚拟成员函数
vf
在类Base
和类Derived
中声明,则直接或间接派生 从Base
中,声明了一个与Base::vf
同名、参数类型列表 (8.3.5)、CV 限定符和 ref 限定符(或不存在相同)的成员函数 VF,则Derived::vf
也是虚拟的(无论它是否 如此声明)并覆盖Base::vf
.
。
即使析构函数不是继承的,派生类中的析构函数也会重写基类析构函数 声明虚拟;见12.4和12.5。
。
重写函数的返回类型应与重写函数的返回类型相同 函数或与函数类的协变。如果函数
D::f
覆盖函数B::f
, 如果函数的返回类型满足以下条件,则它们是协变的:两者都是指向类的指针,都是对
- 类的左值引用,或者都是对 类
- 返回类型
B::f
中的类与返回类型D::f
中的类相同,或者是一个 返回类型中类的明确且可访问的直接或间接基类D::f
- 指针或引用具有相同的 CV 限定条件和返回类型中的类类型
D::f
与返回类型"B::f
"中的类类型具有相同或更少的简历资格。
因为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()
始终调用派生类中名为f
的任何函数B::f
而不是任何函数。
B::f
不会覆盖A::f
,因为它们没有相同的参数类型列表,因此它也不是虚拟的,[class.virtual]/p2:
如果一个虚成员函数
vf
是在类Base
和类Derived
中声明的,直接或间接派生自Base
,则成员函数vf
具有与声明Base::vf
相同的名称、参数类型列表 (8.3.5)、cv 限定符和 ref 限定符(或没有相同),则Derived::vf
也是虚拟的(无论它是否如此声明),并且它覆盖Base::vf
。
因此,派生类方法无论是否具有virtual
说明符,都可以隐式虚拟,前提是它与基类方法的某些属性匹配。在这种情况下,B::f
不是虚拟的,因此pb->f()
使用指针的静态类型,B*
,并调用B::f
而不是C::f
。
- 如何在继承层次结构中调用具有默认参数的构造函数?
- QT C++,从子层次结构调用 main 中的函数
- 无法使用"enable_if"和"is_base_of"将模板函数"operator+"的重载限制到我的类层次结构
- 菱形层次结构中的虚函数重载在 clang 和 gcc 中产生不同的结果
- C++复制可克隆层次结构中的构造函数和赋值
- 模板层次结构中的可选虚拟函数,具体取决于参数
- 如何调用遍历类层次结构的成员函数
- 具有向下强制转换函数指针的类层次结构
- 函数和多个类层次结构
- 在类层次结构中,完美的转发构造函数和复制构造函数之间的冲突
- 设计一个没有虚拟析构函数的多态类层次结构
- 使用模板对类层次结构进行函数重载的这种方式安全吗
- 两次声明纯虚拟函数(在层次结构中的两个类中)是否完全合法
- C++ 中的虚函数层次结构
- 继承层次结构中级中的新虚函数
- 适用于预先存在的类层次结构的函数的最佳模式
- 如果在派生类中定义了虚拟析构函数,但不是层次结构的顶部,该怎么办?C++
- 类的层次结构,试图在基本级别实现函数
- 具有复杂层次结构的decorator模式:导致核心转储的构造函数
- 使用可重写的处理程序函数构建类层次结构