C++中类型转化

来源:互联网 发布:全站简繁体转换js代码 编辑:程序博客网 时间:2024/05/22 15:38

       对象类型向上向下转化(对象转化是对象间的按成员赋值,有新的存储被分配(有新对象产生)

       类型指针向上向下转化(转化后没有得到引得对象,也可以说没有新的存储分配,我们只是通过一个小的(转化后的对象的大小)视角去看待这个对象。因此在诸如对象的释   放 等方面会牵扯一些问题,语言单独支持的虚析构就是为了解决这种转化后对象释放不对称的问题。类层次结构中类型之间的转化不同于普通或内置类型之间的转化,最明显得区别是转化前后两个对象的指针指向的不是相同的的地址。其实可以说:派生类指针向基类指针转化实际上市派生类中基类子对象的地址赋给目标对象指针(图示)

 

 

 

类对象的静态类型(声明时的类型)和动态类型(指向的实际类型,被赋值的类型)

考虑下列初始化 它用一个派生类 NameQuery 对象的地址初始化一个 Query 基类指针
Query *pb = new NameQuery( "sprite" );

如果我们调用在 Query 基类中定义的虚拟函数 如
pb->eval(); // 调用 NameQuery::eval()
则调用派生的 NameQuery 类实例 除了 在 Query 基类中被声明 并且在 NameQuery派类中被改写 的虚拟函数之外, 我们没有办法通过 pb 直接访问 NameQuery 的成员
1 如果 Query 和 NameQuery 都声明了一个同名的非虚拟成员函数, 则通过 pq 调用的总是Query 的实例

2 类似地 如果 Query 和 NameQuery 都声明了一个同名的数据成员 ,则通过 pq 总是访问 Query 的实例
3.如果 NameQuery 引入了一个在 Query 中不存在的虚拟函数 比如 suffix() 那么试图通过 pq 调用它就会导致一个编译时刻错误:
  // 错误: suffix() 不是 Query 的成员
  pb->suffix();

4 类似地 如果我们试图通过 pq 访问 NameQuery 的数据成员或非虚拟成员函数 也会产生一个编译时刻错误:
// 错误: _name 不是 Query 的成员
pb->_name;

在 C++中 基类指针只能访问在该类中被声明或继承的数据成员和成员函数包括虚拟成员函数 ,而与它可能指向的实际对象无关 ,把一个成员函数声明为虚拟的,只推延了
在程序执行期间根据pq 指向的实际类类型, 对于要调用的实例的解析过程


(自己再vc的环境中写代码验证了一番(不知道对不对,自己先记着)派生类从基类那里继承了数据成员,在派生类对象中基类子对象(如果存在虚拟函数的话)的的虚函数表指针与派生类对象的虚函数表指针是一个变量,都存在对象存储空间的最前方。如果派生类对象存在虚拟函数(则有虚函数表指针)而基类没有虚拟函数(没有虚函数表指针),则打印出来的派生类中的基类子对象时是没有此指针的。

如:

class A{
public:
 int a;
 virtual void parent(){}
 virtual void func(){}
 A(int x){a=x;}
};

class B :public A{
public :
 int b;
 virtual void func(){}
 virtual void parent(){}
 virtual void child(){}
 B(int y):A(2){b=y;}
};
 void main()
 {
  B b(1);
  char * pb=(char *)&b;
  A *pa=&b;
  char *pc=(char *)pa;
  for (int i=0;i<sizeof B;i++)
   cout<<(int)pb[i]<<" ";
  cout<<endl;
  for(i=0;i<sizeof A;i++)
   cout<<(int)pc[i]<<" ";
  cout<<endl;
  cout<<"pa="<<pa<<"  "<<"&b="<<&b<<endl;    //比较两个对象(派生类对象和其中的基类子对象的开始地址是否相同)
  //   cout<<sizeof A <<"  "<<sizeof B<<endl;
  
 }

结果为:44  -16  70 0 2 0 0 0 1 0 0 0

                44  -16  70 0 2 0 0 0

                pa=0012ff74  &b=0012ff74

    //44 -16 70 0化成十六进制是0x0046f02c(是虚函数表的地址)

 

 

class A{
public:
 int a;
 A(int x){a=x;}
};

class B :public A{
public :
 int b;
 virtual void func(){}
 virtual void parent(){}
 virtual void child(){}
 B(int y):A(2){b=y;}
};
 void main()
 {
  B b(1);
  char * pb=(char *)&b;
  A *pa=&b;
  char *pc=(char *)pa;
  for (int i=0;i<sizeof B;i++)
   cout<<(int)pb[i]<<" ";
  cout<<endl;
  for(i=0;i<sizeof A;i++)
   cout<<(int)pc[i]<<" ";
  cout<<endl;
  cout<<"pa="<<pa<<"  "<<"&b="<<&b<<endl;    //比较两个对象(派生类对象和其中的基类子对象的开始地址是否相同)
  //   cout<<sizeof A <<"  "<<sizeof B<<endl;
  
 }

结果为:44  -16  70 0 2 0 0 0 1 0 0 0

                2    0   0  0

                pa=0012ff78  &b=0012ff74

    //44 -16 70 0化成十六进制是0x0046f02c(是虚函数表的地址),此时派生类对象有此指针,而基类子对象没有。

 

原创粉丝点击