深入浅出c++中的虚函数
以下知识学习自github.com/Light-City/…
#include<iostream>
class Base {
public:
Base() = default;
virtual void fun()
{
std::cout << "Base::fun" << std::endl;
}
virtual void fun1()
{
std::cout << "Base::fun1" << std::endl;
}
~Base() = default;
};
class Myfun: public Base
{
public:
Myfun()=default;
void fun() override
{
std::cout << "Myfun::fun" << std::endl;
}
void fun1() override
{
std::cout << "Myfun1::fun1" << std::endl;
}
~Myfun()=default;
};
int main()
{
Base* ptr = new Myfun();
ptr->fun();
ptr->fun1();
return 0;
}
运行结果:
Myfun::fun
Myfun1::fun1
从上面的代码可以看出,c++的多态依赖于虚函数,而为了实现虚函数,c++使用一种虚函数表的方式。
基础理论
虚函数表是c++编译器在编译时期为每个有虚函数的类生成的一种静态数组。其中存储着指向派生类覆写函数的函数指针。当程序运行时,在创建类对象的过程中就会设置一个指针(vptr)来指向虚函数表。
实现过程
Base* ptr = new Myfun();
ptr->fun();
在上面的代码中,程序识别出fun函数是一个虚函数,ptr->vptr会指向Myfun函数的虚函数表,随后分辨出调用的是Myfun的fun函数。
虚函数调用步骤:
1. ptr→ vptr
↓
2. vptr → vtable[0]
↓
3. 找到Myfun::fun()
什么函数可以声明为虚函数
1.static成员函数不可以声明为虚函数。static成员函数并不属于类对象或类实例,没有this指针。而虚函数则依赖类对象的vptr,vptr在类的构造函数中生成,需要有this指针来访问它。
2.构造函数不可以声明为虚函数。虽然虚函数表在编译器就已经生成,但访问它需要的vptr却是在程序运行时生成,需要构造函数来创建。而此时访问虚函数又需要有vptr。二者相矛盾。
3,析构函数可以声明为虚函数。
我们来看一个例子
#include<iostream>
class Base {
public:
Base() { std::cout << "Base Constructor\n"; }
~Base() { std::cout << "Base Destructor\n"; }
};
class Myfun:public Base{
public:
Myfun(){ std::cout << "Myfun Constructor\n"; }
~Myfun(){ std::cout << "Myfun Destructor\n"; }
};
int main()
{
Base* base = new Base();
delete base;
std::cout << "--------------------" << std::endl;
Myfun* myfun = new Myfun();
delete myfun;
std::cout << "--------------------" << std::endl;
Base* fun= new Myfun();
delete fun;
return 0;
}
结果:
Base Constructor
Base Destructor
--------------------
Base Constructor
Myfun Constructor
Myfun Destructor
Base Destructor
--------------------
Base Constructor
Myfun Constructor
Base Destructor
如图,我们代码中的fun没有调用Myfun的析构函数,这将会导致内存泄漏。此时我们需要在Base的析构函数加上virtual。此时才可以正常调用基类的析构函数。
纯虚函数和抽象类
以下就是纯虚函数的的声明。
class Entity
{
public:
virtual std::string Getname()=0;
};
纯虚函数会强制继承这个类的子类在内部实现这个函数,同时我们也不能实例化Entity。至少包含一个纯虚函数的类被成为抽象类,而只有纯虚函数(析构函数也可以声明为纯虚函数)的类就是我们常说的c++中的接口类。