Virtual Function是成员函数,其行为在派生类中被覆盖。与非虚函数不同的是,即使没有关于类的实际类型的编译时信息,也会保留重写的行为。如果派生类使用指针或者对基类的引用进行处理,则对被覆盖的虚函数的调用将调用派生类中定义的行为。
#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"
}
//输出
base
derived
base
derived
base
base
虚函数使其类成为多态基类,派生类可以覆盖虚函数。 通过基类指针/引用调用的虚函数将在运行时解析。 也就是说,使用对象的动态类型而不是静态类型。静态类型是指不需要考虑表达式的执行期语义,仅分析程序文本而决定的表达式类型。静态类型仅依赖于包含表达式的程序文本的形式,而在程序运行时不会改变。动态类型是由一个左值表达式表示的左值所引用的最终派生对象的类型。 大致可以这么理解:
抽象类是定义或继承至少一个最终覆盖纯虚函数的类,一个纯虚函数隐含的使其自己的类被定义为抽象类,抽象类不能被实例化,只能通过派生类来覆盖实现所有继承的纯虚函数,如果派生类不覆盖实现所有的纯虚函数,那么程序编译不通过报错。何为纯虚函数?格式如下: declarator virt-specifier(optional) = 0 eg: virtual func(optional) = 0; =0只能出现在声明标识符之后或者可选标识符(virtual、final)之后,不能出现在成员函数定义中。
#include <iostream>
struct Base {
virtual int g();
virtual ~Base() {}
};
struct A : Base {
// ok, declares three member virtual functions, two of them pure
virtual int f() = 0;
//override代表派生类覆盖父类g()方法
virtual int g() override = 0;
virtual int h();
// ok, destructor can be pure too
virtual ~A() = 0;
// error: pure-specifier on a function definition
virtual int b()=0 {}
};
//输出为
virtual int b()=0 {} error: initializer on function does not look like a pure-specifier
struct Abstract {
virtual void f() = 0; // pure virtual
virtual void g() {}; // non-pure virtual
~Abstract() {
g(); // okay, calls Abstract::g()
// f(); // undefined behavior!
Abstract::f(); // okay, non-virtual call
}
};
//definition of the pure virtual function
void Abstract::f() { std::cout << "A::f()\n"; }
struct Concrete : Abstract {
void f() override {
Abstract::f(); // OK: calls pure virtual function
}
void g() override {}
~Concrete() {
g(); // okay, calls Concrete::g()
f(); // okay, calls Concrete::f()
}
};