/* *
* 普通成员函数, 可以只声明不定义.
*
* 虚函数, 必须要有定义, 因为编译器无法确定运行时会使用到哪个虚函数.
*
*
* 当某个虚函数通过指针或引用被调用时, 编译器产生的代码直到运行时才能
*
* 确定应该调用哪个版本的函数. 被调用的函数是与绑定到指针或引用的对象
*
* 相匹配的那个.
*
* 动态绑定只发生在用指针或引用调用虚函数时, 如果直接用普通类型调用函数
*
* 在编译时就可以确定其调用的版本.
*
* 指针或引用的静态类型与动态类型不同, 是C++多态性的根本所在, 只有当我们
*
* 使用指针或引用调用虚函数时, 才会在运行时解析该调用, 也只有在这种情况下
*
* 对象的静态类型和动态类型才会不同.
*
*
* 1. 当在派生类中覆盖了某个虚函数时, 可以再一次使用virtual来指出函数的性质,
*
* 但不是必须, 因为该函数在所有派生类中都为虚函数.
*
* 2. 一个派生类的函数如果覆盖了某个继承而来的虚函数, 则它的形参类型必须与被
*
* 它覆盖的基类函数要完全一致.其返回类型也必须与基类匹配, 除非其返回类型是其
*
* 自身的引用或指针.
*
* override在覆盖未生效时, 会报错.
*
* final可以放在函数声明后, 任何对该函数的覆盖都会报错.
*
*
* 虚函数的默任实参, 派生类和基类中是独立的, 若用基类指针或引用调用某个虚函数,
*
* 那么生效的会是基类中定义的默认实参, 即使该对象的动态类型是派生类.
*
* 如果虚函数使用默认实参, 最好保证派生类和基类中定义的默认实参一致.
*
* 我们可以用域运算符来强行调用某个版本的虚函数, 该行为在编译时完成解析.
*
* 通常只有在成员函数或友元函数中, 需要用域运算符来回避虚函数机制.
*
* 如果一个派生类的虚函数需要调用其基类版本, 如果没有使用域运算符, 就会产生无限
*
* 递归.
*
* */
补充一下, 最近项目中用到的一个例子:
先是基类的定义:
<