在线文档教程
C++
语言 | Language

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。

http://en.cppreference.com/w/cpp/language/virtual