一、抽象基类和纯虚函数
在设计时,常常希望基类仅仅作为其派生类的一个接口,也就是说,仅想对基类进行向上类型转换,使用它的接口,而不希望用户创建一个基类的对象。要做到这一点,可以在基类中加入至少一个纯虚函数,来使基类成为抽象类,如果某人试着生成一个抽象类的对象,编译器会制止他。另外,当继承一个抽象类时,必须实现所有的纯虚函数,否则继承出的类也将是抽象类。
建立公共接口的唯一原因是它能对于每个不同的子类有不同的表示。它建立一个基本的格式,用来确定什么是对于所有的派生类是公共的——除此之外,别无用途。
当实现继承和重新定义一些虚函数时,编译器为新类创建一个新的VTABLE表,并且插入新函数的地址,对于没有重新定义的虚函数使用基类函数的地址,无论如何,对于可被创建的每一个对象(即它的类中不含有纯虚函数),在VTABLE中总有一个函数地址的全集,所以绝对不能对不在其中的地址进行调用(否则结果将会是灾难的)。
二、不能创建一个抽象类的对象
假设我们在一个类中加入一个纯虚函数,则这个类成为抽象类,如按照以下声明:
virtualvoid f() = 0
这样做,等于告诉编译器在VTABLE中为函数保留一个位置,但是在这个位置中不放地址,如果有一个函数在类中被声明为纯虚函数,则VTABLE就是不完全的。而如果一个类的VTABLE是不完全的,当某人试图创建这个类的对象时,编译器就会发出一个错误信息,这样,编译器就保证了抽象类的纯洁性,它就不会被误用了。
当多态地处理对象时,传地址和传值有明显的不同。大部分的都是传地址的,这是因为地址都有相同的长度,传递派生类对象的地址和传递基类的地址是相同的,这是使用多态的目的,即让对基类对象操作的代码也能透明地操作派生类对象。
如果对一个对象进行向上类型转换,而不使用地址或引用,这个对象将会被“切片”,直到剩下来的是适合于目的的子对象。“切片”,实际上是当它拷贝(因为不是传地址或引用)
到一个新的对象时,去掉原来对象的一部分,而不是像使用指针或引用那样简单地改变地址的内容。纯虚函数的应用则会通过一个编译错误来防止对象切片,因为抽象类对象是不能创建的。