C++中基类和派生类之间的转换实例教程
本文实例讲解了C++中基类和派生类之间的转换。对于深入理解C++面向对象程序设计有一定的帮助作用。此处需要注意:本文实例讲解内容的前提是派生类继承基类的方式是公有继承,关键字public。具体分析如下:
以下程序为讲解示例:
#include<iostream> usingnamespacestd; classA { public: A(intm1,intn1):m(m1),n(n1){} voiddisplay(); private: intm; intn; }; voidA::display() { cout<<"m="<<m<<endl; cout<<"n="<<n<<endl; } classB:publicA { public: B(intm1,intn1,intp1):A(m1,n1),p(p1){} voiddisplay(); private: intp; }; voidB::display() { A::display(); cout<<"p="<<p<<endl; } voidprint1(A&a) { a.display(); } voidprint2(B&b) { b.display(); } voidprint3(Aa) { a.display(); } voidprint4(Bb) { b.display(); } intmain() { Aa(3,4); //a.display(); Bb(10,20,30); //b.display(); A*pa; B*pb; pa=&a; //pa->display(); pb=&b; //pb->display(); //pa=&b; //pa->display(); //pb=&a;//错误。派生类指针不能指向基类对象。 //print1(b); //print2(a);//错误。不能用基类对象给派生类引用赋值。 //print3(b); //print4(a);//错误。不能用基类对象给派生类对象赋值。 //pb=pa;//不能用基类指针给派生类指针赋值。 pb=(B*)pa;//可以强制转换,但是非常不安全。 pb->display();//出现安全问题,p无法访问,因为a中没有p成员 system("pause"); return0; }
切记:派生类对象是基类对象,派生类中包含有基类的成员。基类对象不是派生类对象,它不能包含派生类型的成员。
一、派生类到基类的转化
1.派生类对象地址赋值给基类指针
main函数中执行以下代码
Aa(3,4); //a.display(); Bb(10,20,30); //b.display(); A*pa; //B*pb; //pa=&a; //pa->display(); //pb=&b; //pb->display(); pa=&b; pa->display();//会输出1020
pa为基类指针,指向派生类对象是合法的,因为派生类对象也是基类对象。语句会输出派生类对象中基类部分。
注意:这里并不会调用派生类的display函数,调用的是基类的display函数,因为指针pa是基类指针,编译器在编译阶段只知道pa的类型。如果要实现调用派生类的display函数,需要用到虚函数实现多态性。之后的文章会讲到。
进一步解释一下编译时和运行时的区别。
编译时编译器能知道pa的类型为A*,但是不知道它指向了哪个对象,假如有以下语句
Aa(3,4); Bb(10,20,30); A*pa; intnumber; cin>>number; if(number>=0) pa=&a; else pa=&b;
pa指向的对象类型依赖于输入,运行时才输入,所以编译器是没有办法知道pa指向哪个类型的。
2.派生类对象赋值给基类引用
引用跟指针基本没有区别,引用本质上是指针,是个指针常量,具体可以参照我的另一篇C++中的引用和指针的联系和区别
main函数中执行以下代码
Aa(3,4); Bb(10,20,30); print1(b);//会输出1020
形参为基类引用,实参为派生类对象,派生类对象也是基类对象,可以赋值给基类引用。输出派生类中基类部分。
注意:此时对象本身并未复制,b仍然是派生类对象,前面说过了引用就是一个指针。
3.派生类对象赋值给基类对象。
Aa(3,4); Bb(10,20,30); print3(b);
派生类对象基类部分被复制给形参。
注意:实际上没有从派生类对象到基类对象的直接转换。对基类对象的赋值或初始化,实际上在调用函数,初始化时调用构造函数,赋值时调用赋值操作符。
二、基类到派生类的转化
切记:这种转换有可能引发严重的安全问题,编写代码时不要使用。没有基类到派生类的自动转换,原因在于基类对象只能是基类对象,不能包含派生类型的成员。
如果允许用基类对象给派生类对象赋值,那么就可以试图使用该派生类对象访问不存在的成员。
Aa(3,4); Bb(10,20,30); A*pa; B*pb; //print2(a);//错误。不能用基类对象给派生类引用赋值。 //print4(a);//错误。不能用基类对象给派生类对象赋值。 //pb=&a;//错误。派生类指针不能指向基类对象。 pa=&a; pb=&b; //pb=pa;//错误。不能用基类指针给派生类指针赋值。 pb=(B*)pa;//可以强制转换,但是非常不安全。 pb->display();//出现安全问题,p无法访问,因为a中没有p成员
注意到我们使用强制转换时,当派生类添加了基类中不存在的成员时,会出现安全问题。
pb->display();会调用派生类的display函数,但是它指向的内存是基类对象a的内存,p不存在。会出现严重后果。