问个小问题:动态联编和静态联编的区别

hkx88 2004-02-02 10:37:24
如题
...全文
261 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
webrolling 2004-02-02
  • 打赏
  • 举报
回复
跟虚函数有关的,楼上的已经说的很详细了。
byyyyy 2004-02-02
  • 打赏
  • 举报
回复
虚函数
虚函数是动态联编的基础,它是引入派生概念之后用来表现基类和派生类成员函数之间的一种关系的。虚函数在基类中定义,它也是一种成员函数,而且是非静态成员函数。
1. 虚函数的说明
说明虚函数的方法如下:
virtual <类型说明符><函数名>(<参数表>)
关键字virtual说明的函数称为虚函数。这就意味着该成员函数在派生类中可能有不同的实现。当使用这个成员函数操作指针或引用所标识对象来操作虚函数,对该成员函数调用采取动态联编方式,即在运行时进行关联或束定。
动态联编只能通过指针或引用标识对象来操作虚函数。如果采用一般类型的标识对象来操作虚函数,则将擦用静态联编方式调用虚函数。
C++动态联编的处理方式仍能实现静态类型检查,换句话说,函数参数类型错误在编译阶段能够检查出来。
例:以下是采用动态联编实现例1的程序:
#include<iostream.h>
class unstudent
{
protected:
int no;
char name[10];
int fee1,fee2,fee3,fee4,fee;
public:
virtual void calfee()
{
cout<<"学号:";
cin>>no;
cout<<"姓名:";
cin>>name;
fee1=4800;
fee2=1100;
fee3=400;
fee4=200;
fee=fee1+fee2+fee3+fee4;
}
virtual void disp()
{
cout<<"学费:"<<fee1<<endl;
cout<<"住宿费:"<<fee2<<endl;
cout<<"书报费:"<<fee3<<endl;
cout<<"其它:"<<fee4<<endl;
cout<<"总费用:"<<fee<<endl;
}
};
class graduate:public unstudent
{
public:
void calfee()
{
cout<<"学号:";
cin>>no;
cout<<"姓名:";
cin>>name;
fee1=1100;
fee2=400;
fee3=200;
fee=fee1+fee2+fee3;
}
void disp()
{
cout<<"住宿费:"<<fee1<<endl;
cout<<"书报费:"<<fee2<<endl;
cout<<"其它:"<<fee3<<endl;
cout<<"总费用:"<<fee<<endl;
}
};
void fn(unstudent &x)
{
x.calfee();
x.disp();
}
void main()
{
unstudent s1;
graduate s2;
cout<<"大学生收费"<<endl;
fn(s1);
cout<<"研究生收费"<<endl;
fn(s2);
cin.get();
}
这时,程序被正确执行了,而本程序与例1的唯一差别是将unstudent类的calfee()和disp()两个成员函数设置为虚函数。
2. 多继承中的虚函数
在多继承中由于派生类是由多个基类派生而来的,这些基类中既有虚函数,也有非虚函数的普通函数,因此,虚函数的使用不象单继承那么简单。
例3:
#include<iostream.h>
class A
{
public:
virtual void f()
{
cout<<"class A"<<endl;
}

};
class B
{
public:
void f()
{
cout<<"class B"<<endl;
}
};
class C:public A,public B
{
public:
void f()
{
cout<<"class C"<<endl;
}
};
void main()
{
A a,*p1;
B b,*p2;
C c;
p1=&a;
p1->f();
p2=&b;
p2->f();
p1=&c;
p1->f();
p2=&c;
p2->f();
cin.get();
}
3. 虚函数的限制
1) 只有类的成员函数才能说明为虚函数。因为,虚函数仅适用于有继承关系的类对象,所以普通函数不能说明为虚函数。
2) 静态成员函数不能是虚函数。因为,静态成员函数不受限与某个对象。
3) 内联函数不能是虚函数,因为内联函数是不能在运行中动态确定气位置的。即使虚函数在类的内部定义,编译时仍将其看作是非内联的。
4) 构造函数不能是虚函数,因为构造时对象还是一片未定型的空间。只有在构造完成后,对象才能成为一个类的名副其实的实例。
5) 析构函数可以是虚函数,而且通常说明为虚函数。
说明虚函数的目的在于:使用delete运算符删除一个对象时,能确保析构函数被正确的执行。这是因为,设置需析构函数后,可以利用动态联编方式选择析构函数。
byyyyy 2004-02-02
  • 打赏
  • 举报
回复
多态性是面向对象设计的重要特征之一,所谓多态性是指一个名称可以具有多种语义。利用多态性,用户只需发送一般形式的消息,而将所有的实现留给接收消息的对象,对象根据所接受到的消息而做出相应的动作。虚函数是实现多态性的重要在、机制之一。
一、 静态联编和动态联编
在C++中,多态性主要是通过函数重载实现的。重载函数是指程序中对同名函数进行调用时,编译器会根据函数参数的类型和个数,决定该调用哪一段函数代码来处理这个函数调用。这种把函数调用与适当的函数代码相对应的动作,叫做联编。
联编分为静态联编和动态联编。
在编译阶段决定执行哪个同名的被调用函数,称为静态联编。
在编译阶段不能决定执行哪个同名的被调用函数,只在执行阶段才能依据要处理的对象类型来决定执行哪个类的成员函数,这称为动态联编。
多态性也分为静态和动态两种。静态多态性是指定义在一个类或一个函数中的同名函数,它们可根据参数表(类型及个数)区别语义,并通过静态联编实现,例如在一个类中定义不同参数的构造函数以及运算符的重载等。动态多态性是指定义在一个类层次的不同类中的重载函数,它们一般具有相同的参数表,因而要根据指针指向的对象所在类来区别语义,它通过动态联编实现。
例1:
#include<iostream.h>
class unstudent
{
protected:
int no;
char name[10];
int fee1,fee2,fee3,fee4,fee;
public:
void calfee()
{
cout<<"学号:";
cin>>no;
cout<<"姓名:";
cin>>name;
fee1=4800;
fee2=1100;
fee3=400;
fee4=200;
fee=fee1+fee2+fee3+fee4;
}
void disp()
{
cout<<"学费:"<<fee1<<endl;
cout<<"住宿费:"<<fee2<<endl;
cout<<"书报费:"<<fee3<<endl;
cout<<"其它:"<<fee4<<endl;
cout<<"总费用:"<<fee<<endl;
}
};
class graduate:public unstudent
{
public:
void calfee()
{
cout<<"学号:";
cin>>no;
cout<<"姓名:";
cin>>name;
fee1=1100;
fee2=400;
fee3=200;
fee=fee1+fee2+fee3;
}
void disp()
{
cout<<"住宿费:"<<fee1<<endl;
cout<<"书报费:"<<fee2<<endl;
cout<<"其它:"<<fee3<<endl;
cout<<"总费用:"<<fee<<endl;
}
};
void fn(unstudent &x)
{
x.calfee();
x.disp();
}
void main()
{
unstudent s1;
graduate s2;
cout<<"大学生收费"<<endl;
fn(s1);
cout<<"研究生收费"<<endl;
fn(s2);
cin.get();
}
本程序设计了一个unstudent类,其中的calfee()函数用于输入一个大学生的学号和姓名并计算学费,disp()用于显示大学生的费用。graduate类是从unstudent类派生的,其中的calfee()函数用于输入一个研究生的学号和姓名并计算学费,disp()用于显示研究生的费用。
在main()函数中,定义了一个unstudent类的对象s1和一个graduate类的对象s2。当调用fn(s1)函数时,希望输出大学生s1的学费;当调用fn(s2)函数时,希望输出研究生s2的学费。
我们看到执行fn(s1)是正确的,而执行fn(s2)是错误的,这里仍输出一个大学生的学费。
因为函数fn(unstudent &x)在编译时就确定其对象为unstudent,所以调用的x.calfee()和x.disp()均为unstudent类的成员函数,这里采用的是静态联编。
解决这一问题是采用动态联编,即在执行fn(s)时根据s对象来自动确定相应的成员函数,而不是在编译时就确定哪个重载函数被调用。
这种在运行时能依据其类型确认调用哪个函数的能力称为多态性,也就是动态联编。
byyyyy 2004-02-02
  • 打赏
  • 举报
回复
联编是指一个计算机程序自身彼此关联的过程。按照联编所进行的阶段不同,可分为两种不同的联编方法:静态联编和动态联编。
  静态联编

  静态联编是指联编工作出现在编译连接阶段,这种联编又称早期联编,因为这种联编过程是在程序开始运行之前完成的。

  在编译时所进行的这种联编又称静态束定。在编译时就解决了程序中的操作调用与执行该操作代码间的关系,确定这种关系又称为束定,在编译时束定又称静态束定。下面举一个静态联编的例子。

#include

class Point
{
public:
Point(double i, double j) { x=i; y=j; }
double Area() const { return 0.0; }
private:
double x, y;
};
class Rectangle:public Point
{
public:
Rectangle(double i, double j, double k, double l);
double Area() const { return w*h; }
private:
double w, h;
};
Rectangle::Rectangle(double i, double j, double k, double l):Point(i, j)
{
w=k; h=l;
}
void fun(Point &s)
{
cout< }

void main()
{
Rectangle rec(3.0, 5.2, 15.0, 25.0);
fun(rec);
}

该程序的运行结果为:

0


  输出结果表明在fun()函数中,s所引用的对象执行的Area()操作被关联到Point::Area()的实现代码上。这是因为静态联编的结果。在程序编译阶段,对s所引用的对象所执行的Area()操作只能束定到Point类的函数上。因此,导致程序输出了所不期望的结果。因为我们期望的是s引用的对象所执行的Area()操作应该束定到Rectangl类的Area()函数上。这是静态联编所达不到的。

  动态联编

  从对静态联编的上述分析中可以知道,编译程序在编译阶段并不能确切知道将要调用的函数,只有在程序执行时才能确定将要调用的函数,为此要确切知道该调用的函数,要求联编工作要在程序运行时进行,这种在程序运行时进行联编工作被称为动态联编,或称动态束定,又叫晚期联编。

  动态联编实际上是进行动态识别。在上例中,前面分析过了静态联编时,fun()函数中s所引用的对象被束定到Point类上。而在运行时进行动态联编将把s的对象引用束定到Rectangle类上。可见,同一个对象引用s,在不同阶段被束定的类对象将是不同的。那么如何来确定是静态联编还是动态联编呢?C++规定动态联编是在虚函数的支持下实现的。

  从上述分析可以看出静态联编和动态联编也都是属于多态性的,它们是不同阶段对不同实现进行不同的选择。上例中,实现上是对fun()函数参数的多态性的选择。该函数的参数是一个类的对象引用,静态联编和动态联编和动态联编实际上是在选择它的静态类型和动态类型。联编是对这个引用的多态性的选择。
pacman2000 2004-02-02
  • 打赏
  • 举报
回复
动态是在编译时只是记录了要调用的符号表,在运行时再去找符号对应的程序。
静态是编译时就全部集成在了一起,运行时程序就已经都在可执行文件里了。
tlping 2004-02-02
  • 打赏
  • 举报
回复
我觉得动态连编的exe或dll 在运行时可能需要动态加载一些特定的dll,
而静态的不需要,但生成的文件要大很多,
就好像是编译mfc工程时,如果动态链编(在settings中设置Dynamic link)则需要在运行时path路径中可以找到mfc42.dll文件,静态编译的则没有这个需求
fanged 2004-02-02
  • 打赏
  • 举报
回复
动态联编是运行的时候加载代码,静态联编是编译的时候加载代码。

64,680

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧