在《静态联编和动态联编》一文中,我们已经知道动态联编是在虚函数的支持下实现的,也即知道虚函数的作用了,这一讲里我们主要讨论虚函数的格式、条件(什么样的函数才叫虚函数)、调用及在构造函数和析构函数中调用虚函数的注意事项。
虚函数是动态联编的基础。虚函数是成员函数,而且是非static的成员函数。说明虚函数的方法如下:
virtual <类型说明符><函数名>(<参数表>)
其中,被关键字virtual说明的函数称为虚函数。
如果某类中的一个成员函数被说明为虚函数,这就意味着该成员函数在派生类中可能有不同的实现。当使用这个成员函数操作指针或引用所标识对象时,对该成员函数调用采取动态联编方式,即在运行时进行关联或束定。
动态联编只能通过指针或引用标识对象来操作虚函数。如果采用一般类型的标识对象来操作虚函数,则将采用静态联编方式调用虚函数。
下面给出一个动态联编的例子:
#include <iostream.h>
class Point
{
public:
Point(double i, double j) { x=i; y=j; }
virtual 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; }
virtual 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<<s.Area()<<endl;
}
void main()
{
Rectangle rec(3.0, 5.2, 15.0, 25.0);
fun(rec);
}
通过这个例子可以看到,派生类中对基类的虚函数进行替换时,要求派生类中说明的虚函数与基类中的被替换的虚函数之间满足如下条件:
(1) 与基类的虚函数有相同的参数个数;
(2) 其参数的类型与基类的虚函数的对应参数类型相同;
(3) 其返回值或者与基类虚函数的相同,或者都返回指针或引用,并且派生类虚函数所返回的指针或引用的基类型是基类中被替换的虚函数所返回的指针或引用的基类型的子类型。
满足上述条件的派生类的成员函数,自然是虚函数,可以不必加virtaul说明。
总结动态联编的实现需要如下三个条件:
(1) 要有说明的虚函数;
(2) 调用虚函数操作的是指向对象的指针或者对象引用;或者是由成员函数调用虚函数;
(3) 子类型关系的建立。
以上结果可用以下例子证实。
#include <iostream.h>
class A
{
public:
virtual void act1();
void act2()
{
act1();
this->act1();
A::act1();
}
};
void A::act1()
{
cout<<"A::act1() called."<<endl;
}
class B : public A
{
public:
void act1();
};
void B::act1()
{
cout<<"B::act1() called."<<endl;
}
void main()
{
B b;
b.act2();
}
构造函数中调用虚函数时,采用静态联编即构造函数调用的虚函数是自己类中实现的虚函数,如果自己类中没有实现这个虚函数,则调用基类中的虚函数,而不是任何涶生类中实现的虚函数。
下面通过一个例子说明在构造函数中如何调用虚函数。
#include <iostream.h>
class A
{
public:
A() {}
virtual void f() { cout<<"A::f() called.\n"; }
};
class B : public A
{
public:
B() { f(); }
void g() { f(); }
};
class C : public B
{
public:
C() {}
virtual void f() { cout<<"C::f() called.\n"; }
};
void main()
{
C c;
c.g();
}
上面程序的输出结果为:
A::f() called.
C::f() called.
关于析构函数中调用虚函数同构造函数一样,即析构函数所调用的虚函数是自身类的或者基类中实现的虚函数。
一般要求基类中说明了虚函数后,派生类说明的虚函数应该与基类中虚函数的参数个数相等,对应参数的类型相同,如果不相同,则将派生类虚函数的参数的类型强制转换为基类中虚函数的参数类型。
2001-9-13 18:18
附带《C++面向对象基础教程》
文件下载: 点击下载 [114KB],[rar格式,下载 Winrar300sc ]