20140424 父类指针指向子类 子类指针指向父类 父类指针不能访问子类成员(虚函数例外)

1、父类指针指向子类

B b;   A *pa;   pa=&b;//A为父类,B为子类

第一步:子类对象指针&b隐式转换为父类指针

第二步:将转换后的得到的父类指针赋值给pa

2、子类指针指向父类(父类A,子类C)

第一步:父类指针转换为子类时

               假如用pc=dynamic_cast<C *>(pa),则父类A必须必须要有虚函数,转换时会根据pa的具体指向进行判断(动态转换体现于此,如果pa没有指向C类型,结果返回0)。

               假如用pc=static_cast<C *>(pa),则父类A必须不需要有有虚函数,转换时不会判断pa的指向(即使pa没有指向C,转换照样成功,见以下程序2处

第二步:将转换后的得到的子类指针赋值给pc

例子:

#include<iostream>
using namespace std;
class A
{
public:
    virtual void fa()
    {
        cout<<"使用dynamic_cast将父类指针转换为子类时,父类必须要有虚函数,此时父类才是多态类型"<<endl;
    }
};

class B:public A
{

};
class C: public A
{

};

void main()
{
    A a;    B b;    C c;
    A *pa; B *pb; C *pc;
    pa=&b;
    pa->fa();
    cout<<dynamic_cast<B *>(pa)<<endl;//1、父类指针A转化为子类B,因为pa指向b,所以打印出0038FA70
    cout<<dynamic_cast<C *>(pa)<<endl;//2、父类指针A转化为子类C,因为pa没有指向C,所以打印出00000000 (和1比较)
    cout<<static_cast<C *>(pa)<<endl;//3、父类指针A转化为子类指针C,虽然pa没有指向C,但是这里用static_cast,所以打印出0038FA70(和2比较)
    pb=dynamic_cast<B *>(&a);//父类指针转换为子类指针,因为&a并不是B类型,转换失败,所以打印出00000000()
    cout<<dynamic_cast<B *>(&a)<<endl;
}

 

3、父类指针不能访问子类数据成员

class a 
{public: 
int aa}; 
class b:public a 
{public: 
int bb; 

从内存的来看 
如a 
---------| 
|占一个int数据大小--| 
|----(aa数据)------| 
|--------- 
而b则是 
---------|--------- 
|占一个int数据大小--|占一个Int数据大小--| 
|从a中继承而来------|---(bb数据----------| 
|------------------ 
当定义一个基类类型的指针时 
a *p;这时,这个指针指向的是a类型的数据 
当p指针指向派生类的时候,因为p是a类型的指针,所以*p只解释为a类型数据的长度,即 
————————-|--------- 
|占一个int数据大小--|占一个Int数据大小--| 
|从a中继承而来------|-----(bb数据)-------| 
|------------------ 
|------------|----------| 
|-p只指向这个区域_--| 
总结

  • 当基类的指针(P)指向派生类的时候,只能操作派生类中从基类中继承过来的数据
  • 指向派生类的指针,因为内存空间比基类长,会导致严重了后果,所以不允许派生类的指针指向基类。而基类的指针可以指向派生类。(见以下代码)
  • C++的多态性(虚函数)能解决基类指针不能操作派生类的数据成员的问题。    

 

#include<iostream>
using namespace std;
class A  
{
public:  
int aa;
};  

class B:public A  
{public:  
int bb;  
};

void main()
{
    A *pa;
    B bb;
    bb.aa=1;
    bb.bb=2;
    pa=&bb;
    
    cout<<pa<<endl;  
    cout<<(B*)(pa)<<endl;
    cout<(B*)(pa)->aa;//可以访问
    cout<<static_cast<B*>(pa)->aa<<endl;
    //cout<(B*)(pa)->bb;//普通的强制类型转换,不可以访问子类成员bb
    cout<<static_cast<B*>(pa)->bb<<endl;//用了static_cast转换之后,子类成员bb就可以访问了
}

  

 

用C++比较好说明白:       
  1:指针的可访问性是由指针的定义决定的,比如说用BaseClass定义的指针,可访问的范围就是BaseClass的内存区域       
  2:允许用一个指向基类的指针指向派生类,由于被指向的对象(子类)的内存空间大于指针(父类)的可访问空间,所以这种向上映射(子类转化为父类)是安全的       
  3:对象在调用虚函数的时候,是调用父类的函数还是调用派生类的函数,是和对象的类型有关的,比如说一个派生类B,其父类是A,则B的对象调用父类中被声明为VIRTUAL的函数时,被B   所OVERRIDE的函数调用的是B里的函数,而B没有OVERRIDE的函数调用的是基类里的函数

posted @ 2014-04-24 22:05  yexuannan  阅读(3395)  评论(0编辑  收藏  举报