C++ 虚拟函数(virtual 关键字)
1.虚函数(实现类的多态性)
当函数被virtual关键字修饰时,该函数被称为虚函数,虚函数是指一个类中你希望重载的成员函数,当你用一个基类指针或引用指向一个继承类对象的时候,你调用一个虚函数,实际调用的是继承类的版本。虚函数最关键的特点是“动态联编”,它可以在运行时判断指针指向的对象,并正确调用对象的函数。 而函数的重载可以认为是多态,只不过是静态的。注意,非虚函数静态联编,效率要比虚函数高,但是不具备动态联编能力。
只要基函数定义了virtual,继承类的该函数也就具有virtual属性
c++中的函数调用默认不适用动态绑定。要触发动态绑定,必须满足两个条件:第一,指定为虚函数;第二,通过基类类型的引用或指针调用。
如果使用了virtual关键字,程序将根据引用或指针指向的 对象类型 来选择方法,否则使用引用类型或指针类型来选择方法。
- 友元函数 构造函数 static静态函数 不能用virtual关键字修饰;
- 普通成员函数 和析构函数 可以用virtual关键字修饰;
class A{
private:
int i;
public:
A();
A(int num) :i(num) {};
virtual void fun1();
virtual void fun2();
};
class B : public A{
private:
int j;
public:
B(int num) :j(num){};
virtual void fun2();// 重写了基类的方法
};
int main{
A a(1);
B b(2);
A *a1_ptr = &a;
A *a2_ptr = &b;
// 当派生类“重写”了基类的虚方法,调用该方法时
// 程序根据 指针或引用 指向的 “对象的类型”来选择使用哪个方法
a1_ptr->fun2();// call A::fun2();
a2_ptr->fun2();// call B::fun1();
// 否则 程序根据“指针或引用的类型”来选择使用哪个方法
a1_ptr->fun1();// call A::fun1();
a2_ptr->fun1();// call A::fun1();
}
2.纯虚函数
class CShape
{
public:
virtual void Show()=0;
};
何时使用纯虚函数?
(1)当想在基类中抽象出一个方法,且该基类只做能被继承,而不能被实例化;
(2)这个方法必须在派生类(derived class)中被实现;
如果满足以上两点,可以考虑将该方法申明为pure virtual function.
- 纯虚函数为后代类提供可覆盖的接口,但这个类中的版本决不会调用。
- 含有一个或多个纯虚函数的类是抽象基类,抽象基类不能实例化。
- 继承类只有重写这个接口才能被实例化
抽象类的规定
(1)抽象类只能用作其他类的基类,不能建立抽象类对象。
(2)抽象类不能用作参数类型、函数返回类型或显式转换的类型。
(3)可以定义指向抽象类的指针和引用,此指针可以指向它的派生类,进而实现多态性。
3.虚继承
虚继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。间接或直接地继承同一基类,会在子类中存在多份拷贝。这样将存在两个问题:①浪费存储空间;②存在二义性
例:类D继承来自类B1、B2,而类B1、B2都继承来自类A,如左图所示(A为非虚基类):
为了节省内存空间,可以将B1、B2对A的继承定义为虚继承,那么A就成了虚拟基类。如右图所示。
class A{};
class B1 :public virtual A{};
class B2 :public virtual A{};
class D :public B1,public B2{};
上一篇: C++ 多态性 - 虚拟函数 虚拟和覆盖
下一篇: C++ 虚拟函数、覆盖、最终参见本文