多态性是C++的一个重要特性,【不扯淡直接进入正题】
灵活运用多态,首先得知道类之间的继承。 当B继承了A类后,一般都是公有继承。 B的实例化对象的内存空间结构若是了解 就可以合理利用多态了。
A的内存空间我们假定为a,
B的内存空间是这样的结构: a
b新增的地址空间
a+b 就是B实例化对象的地址空间了。
在类的空间里面 都会有虚函数的信息表,【没有虚函数 就没法考虑多态】;A有A的虚函数信息表,B有B的虚函数信息表。
结合下面例子来理解: class A{public: void fun1(){ printf(”A1 ");} virtual void fun2(){printf ("A2 ");} };
class B :public A{ public:void fun1(){ printf(”B1 ");} void fun2(){printf("B2 ");} };
int main()
{
A a; B b;
A* p = &a;
p->fun2();
p = &b;
p-> fun2();
p->fun1();
}
fun2 为虚函数, 第一个输出全在A 里面。跟B 没有关系。 第二个输出解释: p是A类的指针,其寻址空间大小跟A类对象空间大小一致。
当把b的对象地址赋予其的时候。因为其寻址空间 上面已经说明。在其寻址fun2时候,发现其实虚函数,虚函数是运行时候加载的。此时编译器
根据其真实对象的虚函数来选择调用。这是编译器的约定,故而寻址到b的虚函数进行调用。
此时的 p->fun1(); 因为其寻址空间限制,调用的还是A的 fun1。
【有待验证】 题外: 上面的 B *p = &a; 的话 会出现什么结果呢? 解释: 此时p的寻址空间 就是 B对象的空间大小,此时把a对象地址赋予p时候,因为p寻址区间>a对象的内存空间。 会造成p在访问时候出现无效地址的访问,会造成内存错误,一般程序里面出现内存崩溃等情况 就这样。
【真心期待路过的老鸟或者有兴趣的朋友留言沟通,指正,谢谢】
延伸: 【
B *p = (B *)&a;
ptr->fun1();
ptr->fun2();
问这两调用的输出结果。这是一个用子类的指针去指向一个强制转换为子类地址的基类对象。结果,这两句调用的输出结果是B1,A2。
并不是很理解这种用法,从原理上来解释,由于B是子类指针,虽然被赋予了基类对象地址,但是ptr->foo()在调用的时候,由于地址偏移量固定,偏移量是子类对象的偏移量,于是即使在指向了一个基类对象的情况下,还是调用到了子类的函数,虽然可能从始到终都没有子类对象的实例化出现。
而ptr->fuu()的调用,可能还是因为多态性的原因,由于指向的是一个基类对象,通过虚函数列表的引用,找到了基类中foo()函数的地址,因此调用了基类的函数。由此可见多态性的强大,可以适应各种变化,不论指针是基类的还是子类的,都能找到正确的实现方法。】