javaee论坛

普通会员

225648

帖子

355

回复

369

积分

楼主
发表于 2017-06-09 10:01:20 | 查看: 513 | 回复: 1

 虚函数实例剖析:

1   把子类对象以初始化父类对象的方式直接赋值给父类对象(或者以父类对象作为形参,以子类对象作为实参为函数进行传值),就相当于另外新建了一个父类对象,然后调用父类的拷贝构造函数把子类从父类继承下来的成员拷贝一份赋给这个父类对象(父类形参),因为拷贝的是子类从父类继承的父类版本的成员,所以不管父类中被覆盖的成员函数有没有被声明为virtual;当这个父类对象调用被覆盖版本的函数时,都是调用的父类版本的被覆盖的成员函数。

2   把子类对象以初始化的方式赋值给父类引用或取子类对象的地址赋给父类指针(或者以父类指针(引用)作为形参,以子类对象的地址(子类对象)为实参为函数传值(传引用))不会调用拷贝构造函数,这就相当于对子类对象从父类继承而来的成员(仍然是这个子类对象的一部分)取了一个别名 即父类引用。如果父类中被覆盖的成员函数被声明为virtual的话,就相当于为这个别名多指定了子类版本的覆盖函数(并将它设为默认的调用函数,就是说在父类引用或父类指针直接调用这个覆盖函数时会调用子类版本的覆盖函数,如果想调用父类版本的覆盖函数就必须在调用的函数名前加“ 父类名::”)。如果父类中被覆盖的成员函数没有被声明为虚函数,则这个别名(父类引用/指针)只是完全对这个子类对象继承下来的父类版本成员而言,是根本调不到子类版本的覆盖函数的。

3  把子类对象直接赋值给已经存在的父类对象(没有意义),会调用父类的赋值号运算符重载函数把子类从父类继承下来的父类版本的成员赋值给已经存在的父类对象。是不会调用到子类版本的覆盖函数的。

实例验证,代码如下:

< name="code" class="cpp">#include <iostream>using namespace std;class p{ private : int a=12; public : p(){ cout<<"In parent p's constructor"<<endl;} virtual void print(){ cout<<"parent p's menber a= "<<a<<endl;}; p(const p& p1){ cout<<"In parent p copy_structor"<<endl;} virtual ~p(){ cout<<"In parent p destructor"<<endl;} const p& operator=(const p& p2){ cout<<"In parent p's overload \"=\" "<<endl; return (*this); };};class s:public p{ private : int b=100; public : s(){ cout<<"In son s's constructor"<<endl;} void print(){cout<<"son's member b = "<<b<<endl;} s(const s& s1){ cout<<"In son s 's copy_structor"<<endl;} ~s(){ cout<<"In son s's destructor"<<endl;} const s& operator=(const s& s2){ cout<<"In son s's overload \"=\" "<<endl; return (*this); };};void Test1(p p1){ p1.print();}void Test2(p & p2){ p2.print();}void Test2(p * p3){ p3->print();}int main(int argc, const char * argv[]){ { cout<<"测试子类构造的调用顺序"<<endl; s s1; } { cout<<"测试将子类对象赋给父类引用"<<endl; s s1; p &p1=s1; } { cout<<"测试将父类指针指向子类对象"<<endl; p *(p1)=new s; delete p1; } { cout<<"测试以子类对象初始化父类对象"<<endl; s s1; p p1=s1; } { cout<<"测试以父类对象作为形参,子类对象作为实参"<<endl; s s1; Test1(s1); } { cout<<"测试以父类对象的引用作为形参,子类对象作为实参"<<endl; s s1; Test2(s1); } { cout<<"测试以父类对象的指针作为形参,取子类对象的地址作为实参"<<endl; s s1; Test2(&s1); } { cout<<"测试以父类指针指向子类对象,被覆盖函数的调用版本(是子类版本)"<<endl; s s1; p *p1=&s1; p1->print(); } { cout<<"以指向子类对象的父类指针,调用父类自身的被覆盖版本"<<endl; s s1; p *p1=&s1; p1->p::print(); } return 0;}


运行结果如下:




普通会员

0

帖子

300

回复

311

积分
沙发
发表于 2022-12-14 21:22:59

好好好

您需要登录后才可以回帖 登录 | 立即注册

触屏版| 电脑版

技术支持 历史网 V2.0 © 2016-2017