您的位置:首页 > 其它

C++虚函数和纯虚函数的区别

2017-08-01 16:15 253 查看
C++里,有虚函数也有纯虚函数,这两个概念名字很像,但是作用却不同,下面讲一下这两个概念的区别。

虚函数

虚函数主要是用在多态方面。虚函数是在基类中声明函数为virtual,并在子类中重写的函数,虚函数可以通过基类类型的指针调用子类里被重写的虚函数,可以实现多态。

我们先来看一看不用虚函数的情况:

子类函数屏蔽基类函数

#include <iostream>

using namespace std;

class Base
{
public:
void hello()
{
cout << "hello world Base" << endl;

}
};

class Derived : public Base
{
public:
void hello()
{
cout << "hello world Derived" <<endl;
}
};

int main()

{
Base b;
Derived d;

b.hello();
d.hello();
   /*******
   运行结果
hello world Base
hello world Derived
********/

Base *b1;
Base *b2;
b1 = &b;
b2 = &d;

b1->hello();
b2->hello();
/*******
运行结果
hello world Base
hello world Base
********/

}


使用虚函数实现多态

可以看到,虽然把子类类型的值赋给了基类类型指针b2,但是b2->hello()这代码的结果仍然是调用了基类的hello()方法,这是因为,基类指针只能访问对象的基类部分,所以无法调用子类里的hello方法。

这样的话,我们要实现多态,就需要使用虚函数了,将上面的代码稍微改动一下。只需要在基类的hello()方法里前添加关键字virtual就行了。

#include <iostream>

using namespace std;

class Base
{
public:
void hello()
{
cout << "hello world Base" << endl;

}
};

class Derived : public Base
{
public:
virtual void hello()
{
cout << "hello world Derived" <<endl;
}
};

int main()

{
Base b;
Derived d;

b.hello();
d.hello();
   /*******
   运行结果
hello world Base
hello world Derived
********/

Base *b1;
Base *b2;
b1 = &b;
b2 = &d;

b1->hello();
b2->hello();
/*******
运行结果
hello world Base
hello world Derived
********/

}


可以看到,通过虚函数,我们实现了多态。那么虚函数的大致工作原理是什么呢?

虚函数工作原理

先说明下,创建派生类的时候,先调用基类的构造函数,再调用子类的构造函数,一个派生类在内存中大概是这样的:

一一一一一一一

Base

一一一一一一一

Derived

一一一一一一一

Base部分和Derived部分是连接在一起的。两个一起组成了子类对象。

每一个类都有一个虚函数表(v-table),每个对象都有一个虚函数指针(vptr),指向虚函数表。当子类对象被创建后,虚函数指针就会指向子类中覆盖的虚函数。当使用基类指针时,虚函数指针将根据基类指针指向的对象的实际类型,来指向正确的函数。

当然,这个只是大概的步骤,虚函数在每本C++书里都会有介绍,如果想要更详细,深入的了解虚函数,可以去看看一些C++的经典著作。

纯虚函数

定义

纯虚函数是一种特殊的虚函数,它在基类中声明,却只能在派生类中给实现。在基类中声明纯虚函数的语法为:

 virtual void hello() = 0;

引入原因

因为C++没有接口这个关键字,我们想要规定一个类的行为的时候,就需要使用纯虚函数来解决问题,因为虚函数没有要求子类强制重写基类的方法,所以说无法靠虚函数规定子类的行为。而纯虚函数可以要求子类强制重写基类的纯虚方法。含有一个或者多个纯虚函数的类称为抽象类,抽象类无法被实例化。

代码

class IBreath
{
public:
virtual void breath() = 0;
};

class Person : public IBreath
{
public:
void breath()
{
cout << "breathing...... " << endl;
}
};

int main()

{

Person p;
p.breath();
// 运行结果:breathing......
}


假如我们有一个Person类,这个类的所有对象要有一个呼吸的动作,我们声明了一个抽象类IBreath,里面有一个纯虚函数breath(),之后通过Person继承了这个抽象类,强制实现了breath()函数。

总结

可以看出,虚函数可以让子类继承并重写方法,但是没有强制的要求,而纯虚函数强制子类重写该函数,所以,纯虚函数总被当成接口来使用,而虚函数可以在实现多态的时候使用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: