面向对象编程系列二:虚函数基本概念

如果基类希望派生类对它的某些成员函数进行重定义,那么该基类需要将成员函数声明为virtual函数,即虚函数,而不希望被重定义的函数则为普通的非虚函数。

调用虚函数时编译器需要动态绑定以确定究竟要调用的是哪一个类的函数,而触发动态绑定的不仅要求调用的函数是虚函数,还要求必须通过基类类型的引用或指针进行函数调用。

(1)派生类对象可以当做基类对象使用

因为每个派生类对象都包含基类部分,所以可以将基类类型的引用绑定到派生类对象的基类部分,也可以用指向基类的指针指向派生类对象。例如:

double print(const Item_Base&);
Item_Base item;
print(item);

Item_Base* p = &item;
Bulk_Item bulk;
print(bulk);//在需要使用基类对象的地方使用了派生类对象 这是合法的
p = &bulk;//基类指针指向派生类对象

如上所示,可以将基类类型的指针或引用来指向或引用派生类对象,所以,当使用基类类型的指针或引用时,无法确定所使用的对象是基类对象还是派生类对象,但是编译器都会将它当做基类类型对象,这是安全的,因为派生类对象是含有基类子对象的,任何可以在基类对象上执行的操作都可以通过派生类对象使用。

这里有两个概念:静态类型和动态类型,静态类型是指编译时期就能确定的指针类型或引用类型,动态类型是指运行时才能确定的指向或引用的对象的类型。

(2)非虚函数的静态绑定

在这里假设使用的静态类型是基类指针或引用,那么调用的非函数则不管所指向的对象的类型也即动态类型是什么,都是基类中定义的,它是在编译时就已确定了的,即使派生类中对非虚函数进行了重定义,只要静态类型是基类类型,那么调用的都是基类中的成员。

(3)虚函数的动态绑定

虚函数的动态绑定是实现多态的关键,它是指当通过基类指针或引用调用一个虚函数时,这个虚函数是在运行时确定的,由动态类型确定。

如果希望调用的虚函数不是动态类型的而是指定的某一类型,那么可以使用域操作符覆盖虚函数机制:

Item_Base* baseP = &derived;
baseP->Item_Base::func();//调用的是静态类型基类对象的成员函数

注意:虚函数也可以有默认实参,但默认实参的值由静态类型确定,与动态类型无关。

(4)纯虚函数和抽象类

在有些情况下,基类中不能给出虚函数有意义的实现,只能把虚函数的实现留给派生类去实现,例如动物作为一个基类可以派生出老虎、孔雀等类,但是动物本身生成对象却不合理,此时将基类中的函数定义为纯虚函数,含有纯虚函数的基类就成为了抽象类,抽象类是不能创建对象的,它是对多种具有相似性的具体事物的共同特征的一种抽象,主要用来统一管理子对象。纯虚函数的定义方式为:

virtual 函数返回值类型 虚函数名(形参表) = 0;
原文地址:https://www.cnblogs.com/sophia-yun/p/3161305.html