目录
1、多态(4种)
定义:就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。会使程序变得更简单。
①多态的形式:
(1)重载多态——函数重载——运算符重载
(2)包含多态——virtual函数
(3)参数多态——模板
(4)强制多态——强制类型转换(有四种) static_cast const_cast...②多态的条件:
(1)满足覆盖
(2)基类的指针或者引用指向基类对象或派生类对象
2、虚函数的运行原理
- 如果一个类包含了虚函数,不管有多少个虚函数,则只增加一个指针的大小;
- 有了一个VPtr(虚指针),VPtr指向一个虚表(vtable),虚表里面存储本类中虚函数的入口地址(可以把表格当成一个数组);
- 非虚函数1个字节,虚函数4个字节(当前一个指针的大小)。
class A
{
public:
//void ff() {}//非虚函数1个字节,虚函数4个字节(当前一个指针的大小)
virtual void fa() { cout << "A::fa" << endl; }
virtual void fb() { cout << "A::fb" << endl; }
virtual void fc() { cout << "A::fc" << endl; }
};
int main()
{
//cout<<sizeof(A) << endl;
A a;
typedef void(*FUN)();
/*a.fa();
a.fb();
a.fc();*/
FUN pf = NULL;//pf是函数指针类型,先指向空
(int*)(&a);//把a*强转为int*
pf = (FUN) * ((int*)(*(int*)(&a)));
pf();
pf = (FUN) * ((int*)(*(int*)(&a))+1);
pf();
pf = (FUN) * ((int*)(*(int*)(&a))+2);
pf();
}
3、单继承
- A可以调用三个虚函数:fa,ga,ha
class A
{
public:
virtual void fa() { cout << "A::fa" << endl; }
virtual void fb() { cout << "A::ga" << endl; }
virtual void fc() { cout << "A::ha" << endl; }
};
单继承步骤:
① 全盘接收:B把A的虚表直接继承,class B : public A。
②改写:改写A中的虚函数,改为B::fa。
③添加自己的函数:添加了两个自己的虚函数gb,hb。
注意:子类对象不能接收基类对象,子类对象比较多;
- B可以调用5个函数:fa,ga,ha,gb,hb
//B可以调用5个函数:fa,ga,ha,gb,hb
class B :public A//B把A的虚表直接继承过来
{
public:
virtual void fa() { cout << "B::fa" << endl; }//改写A中的虚函数
//添加两个虚函数
virtual void gb() { cout << "B::gb" << endl; }
virtual void hb() { cout << "B::hb" << endl; }
};
int main()
{
//cout<<sizeof(B) << endl;//4
B b;
typedef void(*FUN)();
FUN pf = NULL;//pf是函数指针类型,先指向空
//先给b取个地址
pf = (FUN) * ((int*)(*(int*)(&b)));//B::fa
pf();
pf = (FUN) * ((int*)(*(int*)(&b)) + 1);//A::ga
pf();
pf = (FUN) * ((int*)(*(int*)(&b)) + 2);//A::ha
pf();
pf = (FUN) * ((int*)(*(int*)(&b)) + 3);//B::gb
pf();
pf = (FUN) * ((int*)(*(int*)(&b)) + 4);//B::hb
pf();
}
4、多继承
多继承:在子类的对象中,每个父类都有自己的虚表,将最终子类的虚函数放在第一个,
父类的虚表中,这样做解决了不同的父类类型的指针指向比较清晰。
如果在子类中重写了多个父类的同名同参虚函数,那么在虚表中同样做了修改。
class A
{
public:
virtual void ff() { cout << "A::ff" << endl; }
virtual void ha() { cout << "A::ha" << endl; }
};
class B
{
public:
virtual void ff() { cout << "B::ff" << endl; }
virtual void hb() { cout << "B::hb" << endl; }
};
class C
{
public:
virtual void ff() { cout << "C::ff" << endl; }
virtual void hc() { cout << "C::hc" << endl; }
};
//D继承了三个虚表,谁先继承就挂谁(内存里面)
class D:public A,public B,public C
{
public:
virtual void ff() { cout << "D::fd" << endl; }
virtual void hd() { cout << "D::hd" << endl; }
};
int main()
{
cout << sizeof(D) << endl;//12
D d;
typedef void(*FUN)();
FUN pf = NULL;//pf是函数指针类型,先指向空
pf = (FUN) * ((int*)*(int*)(&d));//
pf();
pf = (FUN) * ((int*)*(int*)(&d) + 1);//
pf();
pf = (FUN) * ((int*)*(int*)(&d) + 2);//
pf();
cout << "第二张虚表" << endl;
pf = (FUN) * ((int*)*(int*)(&d) + 3);//
pf();
pf = (FUN) * ((int*)*(int*)((int*)(&d)+ 1));//
pf();
pf = (FUN) * ((int*)*(int*)((int*)(&d) + 1)+1);//
pf();
pf = (FUN) * ((int*)*(int*)((int*)(&d) + 1)+2);//
pf();
}
5、 覆盖(重写)的条件
覆盖(重写):是指同名同参的函数。
- 最少两个类,必须是父子关系
- 必须是同名同参虚函数,基类写了virtual虚函数,子类里可以不写(子类继承)
6、联编
(1)定义:
联编:是指计算机程序彼此关联的过程,(使一个源程序经过编译、连接,成为一个可执行程序)的过程;在这个联编过程中,需要确定程序中的操作调用(函数调用)与执行该操作函数)的代码段之间的映射关系。
(2)分类:
- 静态联编(是早期绑定)
- 动态联编
联编(捆绑,绑定)——函数调用和函数体联系的过程
早捆绑——在编译时
挖捆绑——在运行时
class A
{
public:
virtual void fn() { cout << "A::fn" << endl; }
virtual void ff() { cout << "A::ff" << endl; }
void fff() { cout << "A::fff" << endl; }
};
class B :public A//B把A的虚表直接继承过来
{
public:
virtual void fn() { cout << "B::fn" << endl; }//改写A中的虚函数
virtual void fb() { cout << "B::fb" << endl; }
void fff() { cout << "A::fff" << endl; }
};
void test1(A* p)
{
p->fn();
}
void test(A& aa)
{
aa.fn();
aa.ff();
aa.fff();
}
int main()
{
A a;
B b;
test(a);
test(b);
test1(&a);
test1(&b);
}
如有错误,敬请指正。
您的收藏与点赞都是对我最大的鼓励和支持!