virtual function specifier
虚函数说明符
大virtual
说明符指定非静态成员函数是虚拟
并支持动态绑定。它只能出现在非静态成员函数%28i的初始声明的decl-说明符-seq中。e.在类定义%29中声明它时。
解释
虚拟函数是可以在派生类中重写其行为的成员函数。相对于非虚拟函数,即使没有关于类的实际类型的编译时信息,重写的行为也会被保留。如果使用指针或对基类的引用处理派生类,则调用重写的虚拟函数将调用派生类中定义的行为。如果使用限定名查找%28,也就是说,如果函数%27s的名称出现在范围解析操作符的右侧::
29%。
二次
#include <iostream>
struct Base {
virtual void f() {
std::cout << "base\n";
}
};
struct Derived : Base {
void f() override { // 'override' is optional
std::cout << "derived\n";
}
};
int main()
{
Base b;
Derived d;
// virtual function call through reference
Base& br = b; // the type of br is Base&
Base& dr = d; // the type of dr is Base& as well
br.f( // prints "base"
dr.f( // prints "derived"
// virtual function call through pointer
Base* bp = &b; // the type of bp is Base*
Base* dp = &d; // the type of dp is Base* as well
bp->f( // prints "base"
dp->f( // prints "derived"
// non-virtual function call
br.Base::f( // prints "base"
dr.Base::f( // prints "base"
}
二次
详细
如果某个成员函数vf
被宣布为virtual
在课堂上Base
,还有一些阶级Derived
,直接或间接地从Base
,具有相同的成员函数声明。
- 名称
- 参数类型列表%28,而不是返回类型%29
- 简历-资格
- 参考-限定符
那么这个函数在类中Derived
也是虚拟
%28是否关键字virtual
在声明%29和覆盖
基础::VF%28,不论单词是否override
在声明%29中使用。
Base::vf
不需要是可见的%28可以声明为私有,或者使用私有继承%29继承可以被重写。
二次
class B {
virtual void do_f( // private member
public:
void f() { do_f( } // public interface
};
struct D : public B {
void do_f() override; // overrides B::do_f
};
int main()
{
D d;
B* bp = &d;
bp->f( // internally calls D::do_f(
}
二次
对于每个虚拟函数,都有最终越野车
,它在执行虚拟函数调用时执行。虚拟成员函数vf
基类的Base
是最后的重写器,除非派生类通过多重继承%29声明或继承%28,这是重写的另一个函数。vf
...
二次
struct A { virtual void f( }; // A::f is virtual
struct B : A { void f( }; // B::f overrides A::f in B
struct C : virtual B { void f( }; // C::f overrides A::f in C
struct D : virtual B {}; // D does not introduce an overrider, B::f is final in D
struct E : C, D { // E does not introduce an overrider, C::f is final in E
using A::f; // not a function declaration, just makes A::f visible to lookup
};
int main() {
E e;
e.f( // virtual call calls C::f, the final overrider in e
e.E::f( // non-virtual call calls A::f, which is visible in E
}
二次
如果一个函数有一个以上的最后过载者,程序是不正确的:
二次
struct A {
virtual void f(
};
struct VB1 : virtual A {
void f( // overrides A::f
};
struct VB2 : virtual A {
void f( // overrides A::f
};
// struct Error : VB1, VB2 {
// // Error: A::f has two final overriders in Error
// };
struct Okay : VB1, VB2 {
void f( // OK: this is the final overrider for A::f
};
struct VB1a : virtual A {}; // does not declare an overrider
struct Da : VB1a, VB2 {
// in Da, the final overrider of A::f is VB2::f
};
二次
具有相同名称但不同参数列表的函数不会覆盖同名的基函数,但是生皮
它:什么时候非限定名查找检查派生类的作用域,查找将查找声明而不检查基类。
二次
struct B {
virtual void f(
};
struct D : B {
void f(int // D::f hides B::f (wrong parameter list)
};
struct D2 : D {
void f( // D2::f overrides B::f (doesn't matter that it's not visible)
};
int main()
{
B b; B& b_as_b = b;
D d; B& d_as_b = d; D& d_as_d = d;
D2 d2; B& d2_as_b = d2; D& d2_as_d = d2;
b_as_b.f( // calls B::f()
d_as_b.f( // calls B::f()
d2_as_b.f( // calls D2::f()
d_as_d.f( // Error: lookup in D finds only f(int)
d2_as_d.f( // Error: lookup in D finds only f(int)
}
二次
If a function is declared with the specifier override, but does not override a virtual function, the program is ill-formed: struct B { virtual void f(int }; struct D : B { virtual void f(int) override; // OK, D::f(int) overrides B::f(int) virtual void f(long) override; // Error: f(long) does not override B::f(int) }; If a function is declared with the specifier final, and another function attempts to override it, the program is ill-formed. struct B { virtual void f() const final; }; struct D : B { void f() const; // Error: D::f attempts to override final B::f }; | (since C++11) |
---|
非成员函数和静态成员函数不能是虚拟的。
不能声明函数模板virtual
这仅适用于本身为模板的函数--类模板的常规成员函数可以声明为虚拟函数。
Virtual functions cannot have any associated constraints. struct A { virtual void f() requires true; // Error: constrained virtual function }; | (concepts TS) |
---|
默认参数在编译时替换虚拟函数。
协变量返回类型
如果函数Derived::f
重写函数Base::f
,则它们的返回类型必须是相同的,或者是协变
.两种类型是共变的,如果它们满足下列所有要求:
- 这两种类型都是指向类的指针或引用%28 lvalue或rvalue%29。不允许多级指针或引用。
- 返回类型中的引用/指向类。
Base::f()
必须是返回类型的引用/指向类的明确和可访问的直接或间接基类。Derived::f()
...
- 返回类型
Derived::f()
必须是平等的或更少的简历-合格的返回类型Base::f()
...
的返回类型中的类。Derived::f
一定是Derived
本身,或必须是完全型在声明点Derived::f
...
当进行虚拟函数调用时,最终覆盖程序返回的类型为隐式转换被调用的重写函数的返回类型:
二次
class B {};
struct Base {
virtual void vf1(
virtual void vf2(
virtual void vf3(
virtual B* vf4(
virtual B* vf5(
};
class D : private B {
friend struct Derived; // in Derived, B is an accessible base of D
};
class A; // forward-declared class is an incomplete type
struct Derived : public Base {
void vf1( // virtual, overrides Base::vf1()
void vf2(int // non-virtual, hides Base::vf2()
// char vf3( // Error: overrides Base::vf3, but has different
// and non-covariant return type
D* vf4( // overrides Base::vf4() and has covariant return type
// A* vf5( // Error: A is incomplete type
};
int main()
{
Derived d;
Base& br = d;
Derived& dr = d;
br.vf1( // calls Derived::vf1()
br.vf2( // calls Base::vf2()
// dr.vf2( // Error: vf2(int) hides vf2()
B* p = br.vf4( // calls Derived::vf4() and converts the result to B*
D* q = dr.vf4( // calls Derived::vf4() and does not convert
// the result to B*
}
二次
虚拟析构器
即使析构函数不被继承,如果基类声明其析构函数virtual
,派生的析构函数总是重写它。这样就可以通过指向基的指针删除动态分配的多态类型对象。
二次
class Base {
public:
virtual ~Base() { /* releases Base's resources */ }
};
class Derived : public Base {
~Derived() { /* releases Derived's resources */ }
};
int main()
{
Base* b = new Derived;
delete b; // Makes a virtual function call to Base::~Base()
// since it is virtual, it calls Derived::~Derived() which can
// release resources of the derived class, and then calls
// Base::~Base() following the usual order of destruction
}
二次
此外,如果一个类是多态
%28声明或继承至少一个虚拟函数%29,其析构函数不是虚拟的,删除它是未定义行为
无论是否存在资源泄漏,如果派生析构函数没有被调用。
一个有用的指导原则是,任何基类的析构函数必须是公共和虚拟或受保护和非虚拟的...
在建造和破坏过程中
当虚拟函数直接或间接地从构造函数或析构函数%28调用时,包括在类的非静态数据成员的构造或销毁期间,例如在成员中。初始化程序列表%29,并且调用的对象是正在构造或销毁的对象,调用的函数是构造函数或析构函数类中的最后一个覆盖器,而不是在一个更派生的类中重写它的函数。换句话说,在构建或破坏过程中,更多派生类并不存在.
当构造一个包含多个分支的复杂类时,在属于一个分支的构造函数中,多态性仅限于该类及其基:如果它获得一个指针或对该子层次结构之外的基子对象的引用,并试图调用一个虚拟函数调用%28e.g。使用显式成员访问%29,该行为未定义:
二次
struct V {
virtual void f(
virtual void g(
};
struct A : virtual V {
virtual void f( // A::f is the final overrider of V::f in A
};
struct B : virtual V {
virtual void g( // B::g is the final overrider of V::g in B
B(V*, A*
};
struct D : A, B {
virtual void f( // D::f is the final overrider of V::f in D
virtual void g( // D::g is the final overrider of V::g in D
// note: A is initialized before B
D() : B((A*)this, this)
{
}
};
// the constructor of B, called from the constructor of D
B::B(V* v, A* a)
{
f( // virtual call to V::f (although D has the final overrider, D doesn't exist)
g( // virtual call to B::g, which is the final overrider in B
v->g( // v's type V is base of B, virtual call calls B::g as before
a->f( // a’s type A is not a base of B. it belongs to a different branch of the
// hierarchy. Attempting a virtual call through that branch causes
// undefined behavior even though A was already fully constructed in this
// case (it was constructed before B since it appears before B in the list
// of the bases of D). In practice, the virtual call to A::f will be
// attempted using B's virtual member function table, since that's what
// is active during B's construction)
}
二次
另见
- 派生类和继承模式
- 覆盖说明符%28自C++11%29
- 最终说明符%28自C++11%29
© cppreference.com
在CreativeCommonsAttribution下授权-ShareAlike未移植许可v3.0。