您的位置:首页 > 编程语言 > C语言/C++

C++基础-虚函数/纯虚函数/普通函数

2017-09-28 18:51 435 查看

序言

本文主要内容:虚函数 + 纯虚函数 + 普通函数 + 虚函数纯虚函数的区别

1. 虚函数

什么是虚函数

被virtual关键字修饰的成员函数,就是虚函数

为什么要使用虚函数

引入虚函数主要为了实现重写多态

虚函数主要作用是为了实现“动态多态性”,父类提供虚函数的实现,为子类提供默认的函数实现。子类可以重写父类的虚函数实现子类的特殊化

说明

对于虚函数来说,父类和子类都有各自的版本,由多态方式调用的时候动态绑定。

虚函数必须实现,否则在链接时将会报错

2. 纯虚函数

什么是纯虚函数

virtual returnType function() = 0;

为什么要使用纯虚函数

也是为了实现“动态多态性

在很多情况下,基类本身生成对象是不合情理的,动物基类可以派生出老虎、孔雀等,但是动物本身的对象却没有实际意义,所以引入了纯虚函数

什么情况下使用纯虚函数

在基类中抽象出一个方法,且该基类只能被继承不能被实例化

这个方法必须在派生类中被实现。

满足以上两点,可考虑声明为纯虚函数。

3. 普通函数

类的普通成员函数。

父类为子类提供了普通函数的强制实现

普通函数是静态编译的,可类内重载但没有运行时多态,只会根据指针引用的“字面值”类对象,调用自己的普通函数。

4. 虚函数和纯虚函数举例

[1] 普通函数举例(静态联编)

/* 例1 */
class A
{
public:
void funPrint()
{
cout<<"function in class A"<<endl;
}
};

class B:public A
{
public:
void funPrint()      //重定义
{
cout<<"function in class B"<<endl;
}
};

int main()
{
A *p;      //基类指针
A a;       //基类对象
B b;       //派生类对象

p = &a;
p->funPrint();

p = &b;
p->funPrint();

b.funPrint();
b.A::funPrint();

return 0;
}

//输出结果:

function in class A
function in class A
function in class B
function in class A

//原因:

(1)静态联编:编译器在编译时就确定好了函数调用
(2)只是普通函数“重定义”,不管引用的实例是哪个类的,调用的时候系统会调用 “左值” 那个对象所属类的方法

>>> 所以基类A指针p最终调用类A的funPrint()函数,输出两个function in class A
>>> 类B实例调用类B的funPrint()函数,类B加上作用域操作符A::调用类A的funPrint()函数

/* 例2 */
#include <iostream>
using namespace std;

class A
{
public:
virtual void fun1() = 0;             //纯虚函数
virtual ~A(){};
virtual void fun2()                  //虚函数
{
cout<<"fun1 in class A"<<endl;
}
void fun3()                          //普通成员函数
{
cout<<"fun3 in class A"<<endl;
}
};

class B:public A
{
public:
virtual ~B(){};
void fun1()                              //纯虚函数实现
{
cout<<"fun1 in class B"<<endl;
}
void fun2()                              //虚函数重写(覆盖)
{
cout<<"fun2 in class B"<<endl;
}
void fun3()                              //普通函数重定义
{
cout<<"fun3 in class B"<<endl;
}
};

int main()
{
A *a = new B;     //抽象类定义指针
a->fun1();
a->fun2();
a->fun3();

cout<<"*******************"<<endl;

B b;               //派生类实例化
b.fun1();
b.fun2();
b.fun3();

delete a;         //释放 new 的对象
return 0;
}

//输出结果:

fun1 in class B           //纯虚函数在基类中声明在子类中实现
fun2 in class B           //动态联编:多态。虚函数在子类中重写,运行时动态绑定
fun3 in class A           //静态联编:编译时就确定好了调用哪个函数。调用左值所属类的方法
*******************
fun1 in class B
fun2 in class B           //动态联编:多态。虚函数在子类中重写,运行时动态绑定
fun3 in class B           //静态联编:调用左值所属类的方法


[2] 虚函数举例(动态联编)

class A
{
public:
virtual void funPrint()
{
cout<<"function in class A"<<endl;
}
};

class B:public A
{
public:
void funPrint()    //或virtual void funPrint(),重写
{
cout<<"function in class B"<<endl;
}
};

int main()
{
A *p;      //基类的指针
A a;
B b;

p = &a;
p->funPrint();

p = &b;
p->funPrint();

return 0;
}

//输出结果:

function in class A
function in class B

//原因:

(1)动态联编:根据实例的不同动态决定调用哪个函数
(2)虚函数的唯一目的就是为了实现多态(动态多态性),编译时不确定调用哪个函数,而是动态的决定要调用哪个函数,即“运行时多态”

>>> 所以基类A指针p指向类A的实例a就调用类A的funPrint()函数,
>>> 指向类B的实例b就调用类B的funPrint()函数


[3] 纯虚函数举例(抽象类)

纯虚函数通常存在于抽象类中,在基类中只是声明一个函数但不去实现它,让派生类去实现

class Vehicle
{
public:
virtual void PrintTyre() = 0; //纯虚函数
};

class Car:public Vehicle
{
public:
virtual void PrintTyre()
{
cout<<"Car tyre four"<<endl;
}
};

class Bike:public Vehicle
{
public:
virtual void PrintTyre()
{
cout<<"Bike tyre two"<<endl;
}
};

int main()
{
Car c;
Bike b;
b.PrintTyre();
c.PrintTyre();
return 0;
}

//输出结果:

Car tyre four
Bike tyre two

//原因:

(1)定义vehicle类,但是具体每种交通工具有多少个轮子是不一定的,就定义为纯虚函数、留待派生类中具体实现


5. 虚函数和纯虚函数的联系与区别

联系

虚函数和纯虚函数可以定义在同一个类中

虚函数和纯虚函数都可以在子类中被重写,以多态的形式调用

虚函数和纯虚函数通常存在于抽象基类中,被子类继承,目的是提供一个统一的接口

虚函数和纯虚函数的定义中不能有static标识符,因为static要求编译时即绑定,而虚函数和纯虚函数运行时才绑定(动态多态性)

实现了纯虚函数的子类,该纯虚函数在子类中就变成了虚函数,子类的子类即孙子类可以覆盖(重写)该虚函数,由多态方式调用的时候动态绑定

区别

定义

虚函数virtual returnType function();

纯虚函数virtual returnType function() = 0;

抽象类

含有纯虚函数的类称为抽象类,而只含有虚函数的类不能称为抽象类

抽象类不能实例化,但可以定义抽象类的指针引用(见例2)

使用

虚函数可以直接使用,也可以子类重写后以多态形式调用

虚函数在基类中只有声明没有定义,是对子类的约束,是“接口继承”,必须在子类中实现该函数才可以使用

Acknowledgements:

http://www.cnblogs.com/xudong-bupt/p/3570304.html

http://www.cnblogs.com/fzhe/archive/2013/01/02/2842513.html

http://blog.chinaunix.net/uid-26851094-id-3327323.html

http://www.cnblogs.com/crazyacking/p/5265634.html(推荐)

http://www.cnblogs.com/bluestorm/archive/2012/08/29/2662350.html

2017.09.28
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: