|
关于C++如何实现虚函数,不需要详细说了,大概说一下。把一个子类对象赋给基类指针,且调用一个虚函数,此时指针会执行子类对象,因为vptr是在对象的开头部分,自然的,会指向vptr指向的函数地址,也就是vtable,vtable是每个类都有的,每个类都会记录该类的虚函数地址,如果重写了基类的虚函数,那vtable里面会更新相应的地址,否则依旧以父类虚函数地址。Vtable里面的次序是严格限定的,以基类里面的次序为次序。注意vptr是继承的。且引入创建默认构造函数一个原因就是创建vptr。
为什么需要virtual这个关键字,原因是如果我们不需要虚函数机制的时候可以不使用,除非到了非得使用的时候,这样子做是为了效率。
纯虚函数可以提供定义,但是不能在类里内联定义,应该在类外定义。即使抽象类所有虚函数都定义了,依然不能创建抽象类对象。子类继承基类切不实现基类的虚函数,编译器会报错。(p378)
如果子类新加了虚函数,会将虚函数地址放在vtable最后。(p379)
对象切片(Object Slicing):如果以传值方式传递,会发生对象切割,把属于子类的东西给切割了。传值只拷贝基类部分。且vptr也转换为基类的vptr。如果参数是抽象类的对象,是无法通过编译的,因为抽象类是不能产生对象的。(p381)
子类可以对父类虚函数进行重载(可以改变参数列表),但不能改变其返回值。如果子类重载了父类的虚函数,则子类对象调用该函数时,隐藏了父类的虚函数。
例外!如果父类的虚函数返回的是父类的指针,此时子类可以改变虚函数返回类型。
抽象类只能作为基类使用,不能声明抽象类对象,构造函数不能是虚函数,析构函数可以是虚函数。
在构造函数调用虚函数,调用的是本类的虚函数,虚函数在构造函数无法发挥作用。
构造函数在类的层次上是从上到下的,所以在类里面调用虚函数,使用的是自己的vptr,因为此时子类还没初始化,所以调用的将是自己的虚函数,而不是子类的。
析构函数中多态机制也不起作用,因为析构函数的调用是从子类往父类析构的,所以如果在基类里调用了虚函数,如果这个虚函数是子类的vptr,那么此时父类应该调用子类的函数,但是此时子类已经被析构掉了。
存在向下转型(父类对象赋给子类指针),但是很危险,可以用dynamic_cast。
|
|