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的函数调用的是基类里的函数