基类和派生类的转换是个很繁琐的工作,先把原理和实际操作的东西写一下,至于怎么应用我这里还没有想明白。
可以参考这篇文章http://blog.csdn.net/jiang1013nan/article/details/4801537
我这篇文章主要是参考c++ primer里面的内容。
我们先明确几个概念,如果我理解的不对希望能有大神指出错误。
第一是,无论哪种继承方式,子类拥有父类的所有成员变量和成员函数,只是访问权的问题。举个例子
#include <iostream> using namespace std; class A { public: int i; }; class B:public A { public: int i; }; int main() { B b; b.i = 10; A &a = b; cout<<a.i<<endl; }大家觉得最后输出的结果是多少?
不是10.而是一个随机值
我的电脑是1629101750。
这说明什么问题呢,B中有两个i,一个是父类的i,一个是自己的i.
但是一般程序设计的人绝对不会这么设计的,因为一般名字一样只要父类有,子类继承就可以了。
但是考试的人,就会这么出题了,这就是为什么大家写了那么多年程序,很多面试题还是没有见过,还是不会,第一是我们基础不牢固,第二是这些地方的实用性其实不是那么大,可能永远不会用到。 不过如果为了提高自己,主要是为了防止出差,很多细节还是需要研究研究,多写写代码,来验证自己的思想是不是正确。
那么派生类转换为基类怎么理解呢?
按照c++ primer 中的说法有两种形式,一种就是给基类赋值,一种是转换为基类的引用或者指针。派生类对象自身并没有变成基类对象。
这两种方式有一些细微的区别,很多时候最好使用常引用最为函数的入参,为什么呢?因为引用少了赋值的操作,效率上面会高一些。
可以查看我写的c++赋值的几种方式,http://blog.csdn.net/mlkiller/article/details/8754330, 直接赋值应该是c语言中保留下来的,在c++中它的作用似乎就不大了,尤其对类和对象的。
大家看看下面的例子
#include<iostream> using namespace std; class A { public: A(); A(A &a); A(int i); void set(A a); int getI(); virtual void print(); private: int i; }; void A::print() { cout<<"A print"<<endl; } A::A() { } A::A(A& a) { i = a.i; } A::A(int i) { this->i = i; } int A::getI() { return i; } void A::set(A a) { i = a.i; } class B: public A { public: B(int i); virtual void print(); private: int k; int i; }; void B::print() { cout<<"B print"<<endl; } B::B(int i) { i = 5; } int main() { A a(10); B b(5); A a1(a); A a2(b); cout<<a1.getI()<<endl; cout<<a2.getI()<<endl; A a_next(20); B b_next(15); a1.set(a_next); a2.set(b_next); cout<<a1.getI()<<endl; cout<<a2.getI()<<endl; A &a3(b); a1.print(); a2.print(); a3.print(); }
我这里的答案是:
10
2293028
20
1628665296
A print
A print
B print
为什么呢?
参考这篇文章http://www.cnblogs.com/witcxc/archive/2012/04/15/2450583.html
子类会调用父类的默认构造函数,根据上面的内容,上题中子类中包含父类的所有元素和方法,但是父类中的默认构造函数没有初始化自己的i,这样i就是个随机值。
子类无论是给父类赋值,还是转换为父类的构造函数,父类中的i永远都没有被初始化,所以结果就是上面的内容。
后面的print函数,我们又回顾了一下虚函数的用法,虚函数只对引用和指针有作用。切记!
这个不可以,这个转换关系不存在。