多种形态,不同的对象来完成同一行为,会产生不同的行为或状态。多态的构成有两个条件:必须通过基类的指针或引用来调用虚函数;被调用的函数必须是虚函数,且派生类要对这个虚函数进行重写。
重载和重写都是多态的一种。函数重载是静态的多态:重载函数是指在同一定义域内,函数名相同,参数,返回值不同的函数,即同一个函数可以做不同的事;虚函数重写是动态的多态,派生类重写虚函数后,父类的指针或引用通过调用不同的虚函数,实现不同的功能。
当一个类中定义了虚函数后,类中会增加一个指针,叫虚函数表指针,指向虚函数表,虚函数表中存着虚函数的地址,通过虚函数表指针找到虚函数表,即可访问虚函数。
具体参考本文?http://t.csdnimg.cn/p7cCX
可以,不过编译器就忽略inline属性,这个函数就不再是内联函数,因为虚函数地址要放到虚表中去,编译阶段就要在内联函数的代码处对内联函数进行展开,虚函数虽然在编译阶段就生成存在代码段中,但是虚函数表指针在类的初始化阶段才进行初始化的。
不能,因为静态成员函数没有this指针,使用类型::成员函数的调用方式无法访问虚函数表,所以静态成员函数无法放进虚函数表。
不能,因为对象中的虚函数表指针是在构造函数初始化列表阶段才初始化的。
可以,并且最好把基类的析构函数定义成虚函数。对于某些场景。虚构函数是虚函数可以更好的释放空间
首先如果是普通调用(即虚函数没有构成多态),是一样快的。如果是多态调用,则调用的普通函数快,因为构成多态,运行时调用虚函数需要到虚函数表中去查找。
虚函数表是在编译阶段就生成的,一般情况下存在代码段(常量区)的。
菱形继承的问题,是由多重继承的父类祖先是同一个父类导致的。由于祖先是一个父类,在继承时都会将这个父类的成员继承过来,所以在派生类中会有数据冗余和成员访问二义性的问题。
解决方案:虚继承,在继承同一个祖先父类的时候采用虚继承,各添加一个虚基表指针,指向虚基表,这个虚基表中存着各对象相对于公共成员的偏移量,各对象可以通过这个偏移量来找到公共成员,进而访问同一份数据,对于继承公共父类祖先的两个类,负担仅仅是多存了两个指针而已。
具体参考:虚继承解决菱形继承的原理
注意:不要把多态中的虚函数表和虚继承中的虚基表搞混了。
当一个类中定义了纯虚函数的时候,这个类就被叫做抽象类。抽象类中的纯虚函数如果不经过派生类重写,就无法实例化出对象!
所用:抽象类强制重写了虚函数,另外抽象类体现出了接口继承关系。