{
public:
virtual void act1(){cout<<"Princess meets Frog"<<endl;act2();}
void act2(){cout<<"Princess kisses Frog"<<endl;act3();}
virtual void act3(){cout<<"Frog turns into Prince"<<endl;act4();}
virtual void act4(){cout<<"They live happily ever after"<<endl;act5();}
void act5(){cout<<"The end"<<endl;}
}; class unhappyTale : public fairyTale
{
public:
void act3(){cout<<"Frog stays a Frog"<<endl;act4();}//overriden
void act4(){cout<<"Princess runs away in disgust"<<endl;act5();}//overiden
void ac5(){cout<<"The not -so -happy end"<<endl;}//hide
};
void main()
{
char c;
fairyTale *tale;
cout<<"which tale would you like to hear(f/u)?";
cin>>c;
if (c == 'f')
{
tale = new fairyTale;//动态分配,将类fairyTale地址赋给tale;
}
else
{
tale = new unhappyTale;
}
tale->act1();
delete tale;
}
结果分析
输入f时
Princess meets Frog
Princess kisses Frog
Frog turns into Prince
They live happily ever after
The end
输入u时结果为
Princess meets Frog
Princess kisses Frog//以上两句由继承关系决定,虽然unhappyTale没有void act1()和void act2(),但是这两个都是继承自fairyTale,且act1()为虚函数
Frog stay a Frog//动态联编tale=new unhappyTale;指向unhappyTale中的虚函数act3()(虽然前面没有关键字virtual,由继承关系决定)
Princess runs away in disgust
The end//调用act5()时,因为是静态联编,所以由fairyTale *tale;决定
*/
/*
在一个基类或派生类的成员函数中可以直接调用该类等级中的虚函数,例如:
{
public:
virtual void act1(){act2();}
void act2(){act3();}
virtual void act3(){act4();}
virtual void act4(){act5();}
void act5(){cout<<"The end"<<endl;}
}; class B:public A
{
public:
void act3(){act4();}
void act4(){act5();}
void act5(){cout<<"All done"<<endl;
}
由于对非虚函数调用是采用静态联编,所以程序不必运行我们就能确定
基类A中的函数act1()中的调用语句:
act2();将调用它所在类中的函数act2(),即A::act2()。同样,基类的成员函数act4()调用A::act5()
派生类B中的成员函数act4()调用 B::act5()
*/
/*
对于虚函数必须具体问题具体分析。例如:
B b;
b.act1();
这时,各成员函数的调用顺序为:
A::act1()->A::act2()->B::act3()->B::act4()->B::act5()
这时可以通过this指针来分析,例如,A::act2()可以使用this指针改写成:
void A::act2()
{
this->act3();
}
在上例情况下,this指向b,所以A::act2()调用B::act3().
A a;
a.act1();
可以使用DAG来分析上例中对虚函数的调用过程,画出最派生类B以及它的基类组成的DAG,在DAG中只列出
虚函数名,我们以类B为例
A{ act1(),act3(),act4()} A{act1()}
继承于A的B 删除基类中被支配的名字如右图
B{ act3(),act4()} B{ act3(),act4()}
右图的DAG决定了实际对象为B的对象情况下虚函数的执行过程。即如果
调用act3()或act4()的话,总调用B中定义的虚函数,而若调用act1(),则总是调用A中的虚函数
*/
/*
可以使用成员名限制来阻止基类的成员函数调用派生类中的虚函数,例如:
void A::act3(){A::act4();}
void B::act3(){A::act4();}
这时,对act4()的调用使用静态联编,即调用A中的act4()
*/