p_test[0] 和 p_test[1] 都是Brass * 类型,如果析构函数不是虚的,那么上面的两个delete都回调用Brass类的析构函数。但p_test[1]是指向派生类的阿,运用基类析构函数消灭派生类对象肯定是不对的。如果将基类析构函数声明为虚就不一样了!它会自动为p_test[1] 调用BrassPlus的析构函数!!!是不是有点智能的味道???虚方法的魅力无限!
联编(binding),静态联编(static binding) 和 动态联编(dynamic binding)1,联编:将源代码中的函数调用解释为执行特定的函数代码块;在C语言中这很简单,因为每个函数名都对应不同的函数。但在C++中,由于重载,编译器必须要根据函数参数和函数名称才能确定使用哪个版本的代码块;2,静态联编:在编译过程中进行联编;3,动态联编:编译器必须生成能够在程序运行时选择正确的虚方法的代码。指针和引用类型的兼容性:1,指向基类的引用或指针可以引用派生类对象,而不需要进行显式类新转换,这种将派生类引用或指针转换为基类引用或指针被称为向上强制转换(upcasting)。相反,将基类引用或指针转换为派生类引用或指针,被称为向下强制转换(downcasting)。如果不进行强制类型转换,则向下强制转换是不被允许的,因为is-a关系通常是不可逆的。假设有一个函数:Usetest(Brass & s),那么程序将对它向上强制转换,所以基类对象和派生类BrassPlus对象作为实参传递给Usetest()函数时,Usetest()函数将根据实参的类型来选择调用哪个代码块。需要注意的是,如果形参是Brass,即Usetset(Brass),那么Brass对象和BrassPlus对象都可以作为实参传递给Usetest(),但如果形参是BrassPlus & 时,即Usetest(BrassPlus & ) ,那么只能将BrassPlus对象作为实参传递给Usetest()!!虚函数的工作原理:对于每个类,编译器都创建一个虚函数地址表(virtual function table,vtbl),表中存储了为类对象声明的虚函数地址,这个表的形式是一个数组。当一个对象被创建之时,编译器为这个对象增加了一个隐藏成元,隐藏成员中保存了一个指向虚函数地址表的指针。例如:基类对象包含一个指针,该指针指向基类中所有虚函数的地址表,派生类对象将包含一个指向另一个独立地址表的指针,如果派生类没有重新定义虚函数,那么这两个地址表是一样的,虽然它们存储在不同的位置。如果派生类提供了虚函数的新定义,那么派生类中的虚函数地址表将保存新函数的地址。所以使用虚函数时,对于每个函数调用,都需执行一项额外的操作,即到调中查找地址,从而也增加了系统开销。每个对象都将增大,增大两为存储地址(隐藏成员:指针)的空间。转载于:https://www.cnblogs.com/busui/p/5801146.html
相关资源:数据结构—成绩单生成器