继承和多态中常见的问题(一)

继承和多态中常见的问题(一)
一、继承:代码的复用。
继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行时间的效果。
1、继承的方式:由于C++中有三种访问限定符,public,private,protected.因此在类与类的继承中也将有这三种方式。继承方式如图:


面试题1.private和protected两者之间的区别是什么?
两者的主要区别是在继承中展现的,如上表可知,private,在继承中外部函数不可以访问,在派生类中也不可以访问。protected在继承中外部函数不可以访问,但在派生类中是可以访问的。
2、派生类对象的构造顺序:派生类给基类构造,要调用基类的构造函数来进行构造
  1. 先构造基类的成员对象
  2. 构造基类自己
  3. 构造派生类的成员对象
  4. 调用派生类的构造函数
3、基类和派生类成员方法之间的关系:
重载:(在同一个作用域下),根据参数列表,返回值,参数个数 
隐藏:基类和派生类在继承结构中,派生类的同名成员把基类的同名成员隐藏了,如果需要调用基类的该方法,在该方法调用前加上基类作用域即可。
覆盖(指的是虚函数表中的覆盖):基类和派生类继承结构中,返回值,参数列表,函数名都相同,而且基类的该函数是virtual函数,那么派生类函数也是virtual函数了。
4、C++类型的强转:
a.const_cast:去掉对象的const属性的强转
b.static_cast:更安全的类型强转,(编译器认为可以支持的强转安全性略高)
c.reinterpret_cast:非常底层的类型强转。(类似于C的强转)
d.dynamic_cast:支持RTTI类型的强转(运行时类型识别的强转)。如果要转的类型试运行时的类型,则返回一个值,否则返回一个空。
5、基类对象和派生类对象之间的转换:编译器默认从下往上的转换)
  • 基类对象->派生类对象      OK
  • 基类指针可以指向派生类对象,但只能访问派生类从基类继承的成员,不能访问派生类特有的成员。         OK
  • 派生类指针指向基类对象  非法访问(由于派生类所占的内存大于基类对象所占的内存)     但是强转之后可以访问。
  • 派生类对象->基类对象     非法访问     
6、虚函数virtual()
class Base
{
public:
   virtual   void show( int ma) {cout<< ma<<end;}
private:
     int ma;
};
class Derive: public  Base
{
public:
   void show( int ma) { cout<<mb<<endl;}
private:
   int mb;
};


面试题2:构造函数是否可以是虚函数?inline函数是否可以是虚函数?析构函数是否可以是虚函数?static函数是否可以是虚函数?
虚函数的条件是: 1、该函数可以取地址
           2、对象必须存在(两者缺一不可)
由以上可以得出:构造函数不可以是虚函数,因为构造函数中没有对象,在调用完构造函数时对象才生成。inline函数不可以是虚函数,因为inline函数不能取地址。析构函数可以是虚函数。用一个基类指针指向堆上的派生类对象,要讲析构函数写为虚函数否则派生类的对象无法析构。
面试题3:动态绑定和静态绑定的区别是什么?
静态绑定:编译时期的绑定。动态绑定:是指运行时期的绑定(两者的不同需要从汇编的角度来看)
Derive der(10);
Base *p = &der;
p->show(10);//call Base::show(int)
p->show();//call  Base::show();
当show()为虚函数时,p->show();汇编指令为:
mov ecx,dword ptr[p]   //先找到vfptr,后找到vftable,找到虚函数的地址
mov eax,dword  ptr[ecx]
call  eax  //动态绑定调用寄存器
动态绑定先找到vfptr,后找到虚表,再找到虚函数的内存(汇编信息),动态绑定可以通过虚指针找到存在虚表上的RTTI(对象类型的运行信息)
静态绑定直接call
7、什么情况下会发生多态的编译/调用?(什么样的情况下会发生动态绑定?)
指针和引用一定会发生动态绑定。
(1)不管是基类指针指向基类对象,或者派生类引用指向派生类对象,都会发生多态。
(2)派生类指针指向基类对象、派生类对象都会发生多态
(3)一定是在虚表中。
8、继承和多态中常见的问题:
(1)派生类是虚函数,基类是普通函数。(基类没有虚指针和虚表)
如果派生类没有从基类继承到vfptr,那么派生类中产生vfptr。该vfptr一定排到最前端;如果从基类几层了vfptr,派生类自己的vfptr不产生,产生的vftable内容合并到基类的vftable中。并且基类指针一定要精确的指向派生类基类部分的起始地址。
(2)继承时构造函数不能给函数默认值,这样派生类中永远得不到该默认值。
(3)继承时在构造函数中调用虚函数,永远都是静态绑定。(因为在此时,还没有对象,不存在虚函数,故不会发生动态绑定)
9、静态的多态和动态的多态有什么样的区别?
静态的多态是在编译时期就存在的,而动态的多态是在运行时体现出的多态。
静态的多态:eg.a.模板(在调用点就要实例化)b.函数的重载
动态的多态:eg.call虚函数 (call   eax)

猜你喜欢

转载自blog.csdn.net/minld/article/details/77279983