计算机二级C 专题 多态性和虚函数


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.

. 虚函数的限制:


一个类中将所有的成员函数都尽可能 地设置为虚函数总是有益的。
它除了会增加一些系统开销,没有其他坏处。但是设置虚函数应注意:

. 只有类的成员函数才能 说明为虚函数。这是因为虚函数仅使用于
有继承 关系的类对象,所以普通函数不能说明为虚函数。

. 静态成员函数不能是虚函数,因为静态成员函数不受限于某个对象。

. 内联函数不能是虚函数,因为内联函数是不能在运行中动态 确定
其位置的。即使虚函数在类的内部定义,编译时仍将其看作非内联。

. 构造函数不能是虚函数,因为构造时,对象 还是一片未定型的空
间。只有在构造完成后,对象才能成为一个类的名副其实的实例。

. 析构函数可以是虚函数,而且通常声明为虚函数。







相关文档
最新文档