class Base
{
public:
virtual void Func1()
{
cout << "Func1()" << endl;
}
private:
int _b = 1;
};
int main()
{
Base b;
return 0;
}
// 1.我们增加一个派生类Derive去继承Base
// 2.Derive中重写Func1
// 3.Base再增加一个虚函数Func2和一个普通函数Func3
class Base
{
public:
virtual void Func1()
{
cout << "Base::Func1()" << endl;
}
virtual void Func2()
{
cout << "Base::Func2()" << endl;
}
void Func3()
{
cout << "Base::Func3()" << endl;
}
private:
int _b = 1;
};
class Derive : public Base
{
public:
virtual void Func1()
{
cout << "Derive::Func1()" << endl;
}
private:
int _d = 2;
};
int main()
{
Base b;
Derive d;
return 0;
}
1.虚函数表本质是一个存虚函数指针的指针数组,这个数组最后放了nullptr
2.派生类虚表的生成:a.先将基类中的虚表内容拷贝一份到派生类虚表中
b.如果派生类重写了基类的虚函数,用派生类自己的虚函数覆盖虚表中的基类的虚函数
c.派生类自己新增的虚函数按其在派生类的声明次序增加到派生类的虚表最后
3.虚表存的是虚函数指针,不是虚函数,虚函数和普通函数一样存在代码段。只是指针存放到了虚表中。
4.满足多态调用,不是在编译期间确定的,是运行起来以后到对象中找的,不满足多态的函数调用是在编译时确认好的。
5.多继承派生类的未重写的虚函数放在第一个继承基类的虚函数表中
1.inline函数不能时虚函数,因为inline函数没有地址,无法把地址放到虚函数表中
2.静态成员不能是虚函数,因为静态成员没有this指针,使用类型::成员函数的调用方式无法访问虚函数表
3.构造函数不能是虚函数,因为对象中的虚函数表指针是在构造函数初始化列表阶段才初始化的
4.析构函数可以是虚函数,但是要分析在什么场景下,最好把基类定义为虚函数
5.对象访问普通函数快还是虚函数快?如果是普通对象一样快,如果是只针对象或者是引用对象,则调用普通函数快,因为构成多态,运行时调用虚函数需要到虚函数表中去查找
6.虚函数在编译阶段就生成,一边情况下存在代码段(常量区)
7.抽象类作用,抽象类强制重写了虚函数,另外抽象类体现出了接口继承的关系。