虚函数纯虚函数

C++ 虚函数和纯虚函数以及抽象类

总结C++虚函数和纯虚函数的定义、区别和用法,抽象类的定义、用法。

虚函数

定义:

通过virtual关键字将类的成员函数定义为虚函数。实现多态的基石。

虚函数并不虚,是实打实的函数,他也是需要进行函数实现的。虚就虚在函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的。

由于编写代码的时候并不能确定被调用的是基类的函数还是哪个派生类的函数,所以被成为"虚"函数。

虚函数定义是为了允许用基类的指针来调用子类的这个函数

原理:

虚函数的实现是由两个部分组成的,虚函数表指针与虚函数表。

定义虚函数之后,会生成一个虚函数表指针,指向虚函数表,虚函数表中则是虚函数指针,存储了虚函数具体的实现位置。如果一个类中有多个虚函数,也只是有一个虚函数表指针,而虚函数表中有多个函数指针。

虚函数表实际是一张类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。

整个流程:

通过对象内存中的虚函数表指针找到虚函数表,接着通过虚函数表找到对应虚函数的实现区域并进行调用。

代码:

class Base

{

public:

virtual void foo()

{

cout<<"virtual Base::foo() is called"<

}

void fun()

{

cout<<"normal Base::fun() is called"<

}

};

class A : public Base

{

public:

virtual void foo()

{

cout<<"A::foo() is called"<

}

void fun()

{

cout<<"normal A::fun() is called"<

}

};

class B : public Base

{

public:

virtual void foo()

{

cout<<"B::foo() is called"<

}

void fun()

{

cout<<"normal B::fun() is called"<

}

};

int main(int argc, char *argv[])

{

Base *base = new Base;

Base *aa = new A;

Base *bb = new B;

base->fun();

aa->fun();

bb->fun();

cout<<"*********************************"<

base->foo();

aa->foo();

bb->foo();

}

normal Base::fun() is called

normal Base::fun() is called

normal Base::fun() is called

*********************************

virtual Base::foo() is called

A::foo() is called

B::foo() is called

普通函数,Base类型的,就是调用的父类的fun()函数。

而虚函数,虽然指向Base的指针,但是调用的却是AB派生类的虚函数,这也是定义虚函数的目的,允许用基类的指针来调用派生类的这个函数。

结论:

当使用类的指针调用成员函数时,普通函数由指针类型决定,而虚函数由指针指向的实际类型决定。

纯虚函数

纯虚函数是真正的虚相当于接口。

纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。

在基类中实现纯虚函数的方法是在函数原型后加"=0"。

virtual void funtion1()=0

基类中不会有默认实现,只能在派生中实现具体。

抽象类

称带有纯虚函数的类为抽象类。

抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。

如果派生类中没有重新定义纯虚函数,而只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。

如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体的类。

抽象类是不能定义对象的。

参考

C++中析构函数为虚函数_c++ 析构函数 虚函数-CSDN博客

C++虚函数详解_https://blog.csdn.net/weixin_43329614/article/deta-CSDN博客