第十三章类和继承:静态联编和动态联编
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:静态联编和动态联编
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
提示:大概内容:
程序调用函数时,将使用哪个可执行代码块呢?编译器负责回答这个问题。将源代码中的函数调用解释为执行特定的函数代码块被称为函数名联编(binding)。在C语言中,这非常简单,因为每个函数名都对应一个不同的函数。在C++中,由于函数重载的缘故,这项任务更复杂。编译器必须查看函数参数以及函数名才能确定使用哪个函数。然而,C/C++编译器可以在编译过程完成这种联编。在编译过程中进行联
编被称为静态联编(static binding),又称为早期联编(early binding)。然而,虚函数使这项工作变得更困难。正如在程序清单13.10所示的那样,使用哪一个函数是不能在编译时确定的,因为编译器不知道用户将选择哪种类型的对象。所以,编译器必须生成能够在程序运行时选择正确的虚方法的代码,这被称为动态联编(dynamic binding),又称为晚期联编(late binding)知道虚方法的行为后,下面深入地探讨这一过程,首先介绍C++如何处理指针和引用类型的兼容性
提示:以下是本篇文章正文内容,下面案例可供参考
一、指针和引用类型的兼容性
在C++中,动态联编与通过指针和引用调用方法相关,从某种程度上说,这是由继承控制的。公有继承建立 is-a关系的一种方法是如何处理指向对象的指针和引用。通常,C++不允许将一种类型的地址赋给另一种类型的指针,也不允许一种类型的引用指向另一种类型:
double x = 1;
int* pi = &x;//赋值无效,指针类型不匹配
long &rl = x;//无效的赋值,不匹配的引用类型
二、使用步骤
1.引入库
代码如下(示例):
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
下面的初始化是允许的:
然而,正如您看到的,指向基类的引用或指针可以引用派生类对象,而不必进行显式类型转换。例如,
BrassPlus dilly("zhang yong",44444,3333);
Brass* pb = &dilly; //ok
Brass&rb = dilly ;//ok
将派生类引用或指针转换为基类引用或指针被称为向上强制转换(upcasting),这使公有继承不需要进行显式类型转换。该规则是is-a关系的一部分。BrassPlus对象都是Brass对象,因为它继承了Brass 对象所有的数据成员和成员函数。所以,可以对 Brass对象执行的任何操作,都适用于BrassPlus对象。因此,为处理 Brass 引用而设计的函数可以对 BrassPlus 对象执行同样的操作,而不必担心会导致任何问题。将指向对象的指针作为函数参数时,也是如此。向上强制转换是可传递的,也就是说,如果从BrassPlus 派生出BrassPlusPlus类,则Brass指针或引用可以引用Brass对象、BrassPlus对象或 BrassPlusPlus 对象。
相反的过程–将基类指针或引用转换为派生类指针或引用–称为向下强制转换(downcasting)。如果不使用显式类型转换,则向下强制转换是不允许的。原因是is-a关系通常是不可逆的。派生类可以新增数据成员,因此使用这些数据成员的类成员函数不能应用于基类。例如,假设从Employee 类派生出 Singe类,并添加了表示歌手音域的数据成员和用于报告音域的值的成员函数range(),则将rage()方法应用于Employee 对象是没有意义的。但如果允许隐式向下强制转换,则可能无意间将指向 Singer 的指针设置为一个Employee对象的地址,并使用该指针来调用range()方法(参见图13.4)。
函数都调用虚方法 ViewAcct():
对于使用基类引用或指针作为参数的函数调用,将进行向上转换。请看下面的代码段,这里假定每个
void fr(Brass& rb);//use rb.ViewAcct()
void fp(Brass* pb);//uses pb->ViewAcct()
void fv(Brass b);//uses b.ViewAcct()
int main()
{
Brass b("zhang yong",12345,6789);
BrassPlus bp("Betyt,z",2222,2222.0);
fr(b);//uses Brass::ViewAcct()
fr(bp);//uses BrassPlus::ViewAcct()
fp(b);//uses Brass::ViewAcct()
fp(bp);//uses BrassPlus::ViewAcct()
fv(b);//uses Brass::ViewAcct()
fv(bp);//uses Brass::ViewAcct()
...
}
按值传递导致只将 BrassPlus对象的 Brass 部分传递给函数 fv()。但随引用和指针发生的隐式向上转换导致函数 f()和 ()分别为 Brass 对象和 BrassPlus对象使用 Brass::ViewAcct()和 BrassPlus::ViewAcct()。隐式向上强制转换使基类指针或引用可以指向基类对象或派生类对象,因此需要动态联编。C++使用虚成员函数来满足这种需求。
把上面的例子运行,测试结果
总结
提示:这里对文章进行总结:
对运行结果做总结
1,fr的引用,执行基类和派生类指向正常。
2,fp指针,直接报错没法运行
3,fv的传类,虽然不报错都能运行,但是函数指向是基类函数,这个需要注意