c++ 访问类的非虚函数 一个有违常理现象

class wnd
{
public :
 void display()
 {
  printf("wnd/n");
 }
};

 

 

class _list //:public wnd
{
public:
 _list()
 {
  i=1;
  j=3;
 }
 void display()
 {
  printf("list/n");
 }
 virtual fun()
 {
  printf("virtual _list/n");
 }
 void hello()
 {
  printf("_list say hello/n");
 }
 int i;
 int j;
};
class _view //:public wnd
{
public:
 _view()
 {
  i=2; 
 }
 void display()
 {
  printf("view/n");
 }
 _list &getlist()
 {
  //return *((_list *)this);
  return (_list &)*this;
 }
 virtual fun()
 {
  printf("virtual _view/n");
 }
 int i;
};
int main(int argc, char* argv[])
{
 _view v;
 v.getlist().display();
 printf("%d/n",v.getlist().i);
 v.getlist().fun();
 v.getlist().hello(); // 并没构造_list,但仍可调用_list::hello
 printf("%d/n",v.getlist().j);
 return 0;
}

 

 

 

结果:
list
2
virtual _view
_list say hello
1245120       这里是个随机值,并不是预想中的3

 

 

 

由上可以得出
1、对"指针"或"引用"的强制转换可以是任意的,编译器不会检查
如果改成 _list l = (_list)v; 就编译不过去
2、调用某类的公共成员函数并不需要借助类的具体实实例
比如要调用_list::hello,按c++的语法,必须先构造_list实例;
但实际上hello函数是独立于_list之外的,即使没构造_list,它也存在
你可以把它当作是一个全局函数。
例如:
假设_list::hello在内存在地址是0x40100
v.getlist().hello(); 这行代码编译器直接把它编译成对call 0x40100

 

 

 

3、v.getlist() 这行代码里面有没有构造 _list 实例
没有,确实是_view实例指针,由
printf("%d/n",v.getlist().i);   显示 2
v.getlist().fun(); 显示_list say hello
可以看出,类实例里面只包含成员变量和虚函数表,这是大家都知道的
而这行printf("%d/n",v.getlist().j); 显示1245120更说明这点
v.getlist().j的访问实际已超出了_view实例的内存范围

  后来为了验证函数与数据的存储写了个测试程序:
#include "stdafx.h"

 

 

 

class NewClass
{
public:
 void hello() {printf("%d/n", a);};
protected:
private:
 int a;
};

 

 

 

int main(int argc, char* argv[])
{
 NewClass *p = NULL;
 p->hello();
 printf("Hello World!/n");
 return 0;
}
  注意,这时程序是会报错的,因为数据成员a根本不存在,访问了野指针,而如果将hello()函数改为一个空函数,则一切运行正常,因为对hello函数的寻址并非通过p的偏移量去查询的(即hello函数并不处于对象的内存结构中,估计在处理调用成员函数时,编译器是将对象的this指针作为一个默认的参数传递给了函数),而对数据p->a的寻址则是通过偏移量去找的,这样一来,NewClass对象的内存结构也就清晰了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值