计算机二级C 专题 多态性和虚函数
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1、 静态联编和动态联编:
. 联编:是指一个计算机程序自身彼此关联的过程。按联编所进行的
阶段不同,可分为两种不同的联编方法。一种是静态联编,一种是动
态联编。
. 静态联编:联编工作出现在编译连接阶段,这种联编过程在程序开
始运行之前完成。
例如:一个静态联编的例子。
#include
class Point
{
public:
Point(double I,double j)
{ x=I;y=j;}
double Area(){return 0.0;}
private:
double x,y;
};
class Rectangle :public Point
{
public:
Rectangle(double i,double j,double k,double l);
Double Area()
{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);
}
分析程序:在 fun() 函数中, s 所引用对象执行的 Area() 操作被关
联到 point::Area() 的实现代码上。这是静态联编的结果。在程序编
译阶段,对 s 所引用 的对象所执行 的 Area() 操作只能束定到
point 类的函数上。
所以执行结果为: 0
. 动态联编:有时编译程序在编译阶段,并不能确切知道将要调用的
函数,只有在程序执行时才能确定将要调用的函数,为此,要确切知
道调用的函数,要求联编工作要在程序运行时进行,这种在程序运行
时进行联编工作被称为动态联编。
动态联编是在虚函数的支持下实现的。
所以静态联编和动态联编也都属于多态性,它们是在不同阶段对不同
实现进行的选择。
2、 虚函数:(是成员函数,且是非 static 的)
. 格式: virtual < 类型说明符 >< 函数名 >(< 参数表 >)
. 说明:①如果某类中的成员函数被说明 为虚函数,就意味着该成
员函数在派生类中可能有不同的实现。当使用这个成员函数操作 指
针或引用 所标识对象时,对该成员函数调用采用动态联编方式,即
在运行时进行束定。
. 态联编只能通过指针或引用标识对象来操作虚函数。若采用一般类
型的标识对象来操作虚函数,则采用静态联编方式调用虚函数。
例如:一个动态联编的例子:
#include
class point
{
public:
point(double I,double j)
{x=I;y=j;}
virtual double Area()
{return 0.0;}
private:
double x,y;
};
class Rectangle:public point
{
public:
Rectangle(double I,double j,double k,double l);
Virtual double Area()
{
return w*h;
}
private:
ouble w,h;
};
Rectangle::Rectangle(double I,double j,
double k,double l):point(I,j)
{
w=k;h=l;
}
void fun(point &s) // 被动态联编
{
cout<
REA()<< P>
}
void main()
{
Rectangle rec(3.0,5.2,15.0,25.0);
Fun(rec);
}
输出结果: 375
. 派生类中对基类的虚函数进行替换时,要求派生类中说明的虚函数
与基类中被替换的虚函数之间满足如下条件:
. 与基类的虚函数有相同的参数个数。
. 其参数的类型与基类的虚函数的对应参数类型相同。
. 其返回值或者与基类虚函数相同,或者都返回指针或引用。
满足上述条件的派生类的成员函数,自然是虚函数,可以不加 virtual.
例如:分析下列程序输出结果,并回答问题:
#include
class A
{
public:
virtual void act1();
void act2()
{
act1();
}
};
void A::act1()
{ cout<<”A::act1() called.”<< P>
class B:public A
{
public:
void act1();
}
void B::act1()
{cout<<”B::act1() called.”<< P>
void main()
{
B b;
b.act2();
}
回答问题:①该程序执行后的输出结果是什么?为什么?
答: B::act1() called.
因为 B 是 A 的派生类, act1() 是 A 类的虚函数 , 类 B 中的
act1() 自然是虚函数。在 main() 函数中, b.act2(), 调用类 B 中的
act2() 函数, B 是派生类,实际上调用 A::act2(), 而 A::act2() 函数
的实现中调用 act1(), 由于有两个 act1() 函数,并且是虚函数,产生
了动态联编,根据运行情况,选择了 B::act1();
. 如果将 A::act2() 的实现改为:
void A::act2()
{
this → act1();
}
输出结果如何?
答: B::act1() called.
因为 this 是指向操作该成员函数的对象的指针。
. 如果将 A::act2() 的实现改为:
void A::act2()
{
a::act1();
}
输出结果如何?
答: A::act1() called.
. 虚函数的限制:
一个类中将所有的成员函数都尽可能 地设置为虚函数总是有益的。
它除了会增加一些系统开销,没有其他坏处。但是设置虚函数应注意:
. 只有类的成员函数才能 说明为虚函数。这是因为虚函数仅使用于
有继承 关系的类对象,所以普通函数不能说明为虚函数。
. 静态成员函数不能是虚函数,因为静态成员函数不受限于某个对象。
. 内联函数不能是虚函数,因为内联函数是不能在运行中动态 确定
其位置的。即使虚函数在类的内部定义,编译时仍将其看作非内联。
. 构造函数不能是虚函数,因为构造时,对象 还是一片未定型的空
间。只有在构造完成后,对象才能成为一个类的名副其实的实例。
. 析构函数可以是虚函数,而且通常声明为虚函数。