1.多态相关概念及使用时需要注意问题。
C++中类的继承中有多态性的概念,所谓的多态就是在类里使用虚函数后,用父类作为对象指针,来正确的调用不同子类或父类来作为相应虚函数。虚基类实际就是继承时使用virtual关键字来定义,为的是让在多重继承时遇到相同的基类时只保留一份,以确定其使用那个类。
2.多态原理。
当使用基类的指针或引用调用重写的虚函数时,当指向父类调用的就是父类的虚函数,指向子类调用的就是子类的虚函数
3.什么是动态联编,什么静态两边。
动态联编 和 静态联编 都是多态性的一种体现
联编是指一个计算机程序自身彼此关联的过程,在这个联编过程中,需要确定程序中的操作调用(函数调用)与执行该操作(函数)的代码段之间的映射关系;按照联编所进行的阶段不同,可分为静态联编和动态联编;
静态联编:
是指联编工作是在程序编译连接阶段进行的,这种联编又称为早期联编;因为这种联编是在程序开始运行之前完成的;
在程序编译阶段进行的这种联编又称静态束定;在编译时就解决了程序中的操作调用与执行该操作代码间的关系,确定这种关系又被称为束定;编译时束定又称为静态束定;
动态联编:
编译程序在编译阶段并不能确切地知道将要调用的函数,只有在程序执行时才能确定将要调用的函数,为此要确切地知道将要调用的函数,要求联编工作在程序运行时进行,这种在程序运行时进行的联编工作被称为动态联编,或动态束定,又叫晚期联编;C++规定:动态联编是在虚函数的支持下实现的;
4.单继承/多继承/菱形继承/菱形虚拟继承。多态场景下对象模型
单继承:当子类与父类构成多态时,子类继承父类的虚表之后,子类虚表里虚函数在内存里的存储情况
多继承:
当一个子类继承多个父类时构成多继承,此时子类会继承这些父类的虚表,子类虚表里虚函数在内存里的存储情况。
菱形继承:
class A
{
public:
virtual void f1()
{
cout<<"A::f1()"<<endl;
}
virtual void f2()
{
cout<<"A::f2()"<<endl;
}
public:
int _a;
};
class B:public A
{
public:
virtual void f1()
{
cout<<"B::f1()"<<endl;
}
virtual void f3()
{
cout<<"B::f3()"<<endl;
}
public:
int _b;
};
class C:public A
{
public:
virtual void f1()
{
cout<<"C::f1()"<<endl;
}
virtual void f4()
{
cout<<"C::f4()"<<endl;
}
public:
int _c;
};
class D:public B,public C
{
public:
virtual void f1()
{
cout<<"D::f1()"<<endl;
}
virtual void f5()
{
cout<<"D::f5()"<<endl;
}
public:
int _d;
};
//打印虚函数表
typedef void(*V_FUNC)();
void PrintVtable(int* vtable)
{
printf("vtable:%p\n",vtable);
int** pvtable=(int**)vtable;
for(size_t i=0; pvtable[i]!=0;i++)
{
printf("vtable[%u]:0x%p->",i,pvtable[i]);
V_FUNC f=(V_FUNC)pvtable[i];
f();
}
cout<<"------------------------------------\n";
}
void test()
{
D d;
d.B::_a=5;
d.C::_a=6;
d._b=1;
d._c=2;
d._d=3;
PrintVtable(*(int**)&d);
PrintVtable(*(int**)((char*)&d+sizeof(B)));
}
int main()
{
test();
return 0;
}
在普通的菱形继承中,处于最先的D类型的对象d,它继承了B,C,并且B,C中分别保存了一份来自继承A的变量;除此之外,B,C还存了虚表指针,通过它可以找到虚表中存的虚函数地址,最后,d对象还存放了自己定义的变量和继承B,C自己定义的变量。
菱形虚拟继承:
菱形虚拟继承与菱形继承的区别在于,B,C继承A的公共成员a,既不存储在
B里,也不存储在C里,而是存储在一块公共的部分,而会将B,C相对于这个变量的偏移地址(这里的偏移量地址叫做虚基表)存在B,C里。所以说,对象d里的B,C里存放了虚表指针、虚基表指针、自己的变量。