您的位置:首页 > 编程语言 > C语言/C++

C++静态联编和动态联编

2018-01-31 16:57 225 查看
所谓联编就是:程序调用函数时,编译器通过某种方法确定具体要执行的代码块的过程。分为静态联编和动态联编。在C语言中,这显得很简单,因为每个函数名对应于不同的函数,所以根据函数名就可以确定具体要执行的代码块。而在C++中,有了函数重载,类继承中的虚函数等特性之后,这个过程就变得很复杂了。

在编译过程中进行联编的就是静态联编,在程序运行时才确定要执行哪个代码块的话就是动态联编。

在类继承中指针和引用的兼容性

通常,C++是不允许一种类型的指针或引用指向另一种类型,但在类继承中是例外。基类的指针和引用是可以指向派生类的对象的,不需要进行显示类型转换。这是可以理解的,因为派生类拥有基类的所有数据成员和成员函数,则相对基类做出的所有操作派生类都可以“胜任“。但反过来,如果想要将派生类的指针或引用指向基类对象,则必须显示类型转换。

虚成员函数和动态联编

使用动态联编的一个例子就是虚成员函数。虚函数是实现多态的一种方法。
#include<iostream>
#include<cstdio>
using namespace std;

class A
{
public:
virtual void output()			//将基类成员函数定义为虚函数
{
cout << "A\n";
}
};

class B :public A
{
public:
virtual void output()
{
cout << "B\n";
}
};

int main()
{
A a;
B b;

A *p1 = &a;				//如果是虚函数,则根据指针指向的对象的具体类型来确定要调用的函数版本
A *p2 = &b;				//如果不是虚函数,则根据指针类型确定要调用的函数版本,引用也是一样道理

p1->output();			//输出A
p2->output();			//输出B

return 0;
}
如果不是虚函数,则根据指针类型确定要调用的函数版本,因此这在编译时就能知道,所以编译器对非虚函数使用静态联编。而对于虚函数,只能在程序运行时才能知道具体指向的对象的类型,所以编译器对虚方法使用的是动态联编。在基类中的虚函数,在派生类中也会自动为虚函数,而无论派生类中有没有添加关键字virtual。
在默认情况下,编译器优先选择静态联编。动态联编必须采取一些方法跟踪基类指针或引用指向的对象类型,这增加了额外的处理开销。

虚函数的工作原理:
虚函数的工作原理随编译器的不同会有些许差异,下面介绍通常的做法。
对于虚函数的处理,编译器通常会为每个对象添加一个隐藏的指针成员,该指针指向的是一个数组,数组中包含了一系列虚函数的地址。这个数组就是虚函数表。虚函数表中存储了类对象声明的一系列虚函数的地址。
在基类中包含一个指向虚函数表的指针,在派生类中也包含一个指向自己的虚函数表的指针。在派生类中,如果没有重写基类的部分虚函数,则对于这部分虚函数在它自己的虚函数表中的地址将和基类中的虚函数表中的地址相同。对于那些重写了的虚函数,在虚函数表中的地址将指向这些新的函数的地址,和基类的不同。另外,如果派生类还新定义了新的虚函数,则该函数的地址也会被添加到虚函数表中。
调用虚函数时,程序将首先查看对象的隐藏指针成员,根据它得到虚函数表,从而得到特定的要执行的函数的入口地址。
从虚函数的工作原理可以看出,非虚函数的效率较高。虚函数有额外的开销(存储空间和查找地址的时间开销等)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: