![]() ![]() |
|
二级C++多态性:多态性和虚函数 | |
作者:佚名 文章来源:不详 点击数 更新时间:2008/4/18 14:40:14 文章录入:杜斌 责任编辑:杜斌 | |
|
|
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< } 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.”< class B:public A { public: void act1(); } void B::act1() {cout<<”B::act1() called.”< 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. • 虚函数的限制: 一个类中将所有的成员函数都尽可能 地设置为虚函数总是有益的。它除了会增加一些系统开销,没有其他坏处。但是设置虚函数应注意: • 只有类的成员函数才能 说明为虚函数。这是因为虚函数仅使用于有继承 关系的类对象,所以普通函数不能说明为虚函数。
• 静态成员函数不能是虚函数,因为静态成员函数不受限于某个对象。 • 内联函数不能是虚函数,因为内联函数是不能在运行中动态 确定其位置的。即使虚函数在类的内部定义,编译时仍将其看作非内联。 • 构造函数不能是虚函数,因为构造时,对象 还是一片未定型的空间。只有在构造完成后,对象才能成为一个类的名副其实的实例。 • 析构函数可以是虚函数,而且通常声明为虚函数。 |
|
![]() ![]() |