找回密码
 注册
搜索
热搜: 回贴
  • 前程无忧官网首页 有什么好的平台可以
  • 最新的销售平台 互联网营销的平台有哪
  • 制作网页的基本流程 网页制作和网页设
  • 【帝国CMS】输出带序号的列表(数字排
  • 网站建设公司 三一,中联,极东泵车的
  • 织梦 建站 织梦网站模版后台怎么更改
  • 云服务官网 哪些网站有免费的简历模板
  • 如何建网站要什么条件 建网站要用什么
  • 吉林市移动公司电话 吉林省退休人员网
  • 设计类毕业论文 网站设计与实现毕业论
查看: 1192|回复: 9

[求助] 关于继承与转换

[复制链接]
发表于 2009-11-4 00:28:03 | 显示全部楼层 |阅读模式 IP:江苏扬州
#include <iostream>
using namespace std;
class a
{
public:
a();
void display();
};
a::a()
{
cout<<"a.............."<<endl;
}
void a::display()
{
cout<<"a::display"<<endl;
}

class b : public a
{
public:
b();
void display();
};
b::b()
{
cout<<"b.............."<<endl;
}
void b::display()
{
cout<<"b::display"<<endl;
}
class c : public a
{
public:
c();
void display();
};
c::c()
{
cout<<"c.............."<<endl;
}
void c::display()
{
cout<<"c::display"<<endl;
}
int main(void)
{
b* objb = new b;
c* objc = (c*)objb;
objc->display();
return 0;
}
执行结果:
a..............
b..............
c::display
我想知道在转换的时候它是如何转换的,原理是什么,在内存中是如何来分配的?
如果将程序改成这样,将a中的display改在虚函数,则这样:
#include <iostream>
using namespace std;
class a
{
public:
a();
virtual void display();
};
a::a()
{
cout<<"a.............."<<endl;
}
void a::display()
{
cout<<"a::display"<<endl;
}

class b : public a
{
public:
b();
void display();
};
b::b()
{
cout<<"b.............."<<endl;
}
void b::display()
{
cout<<"b::display"<<endl;
}
class c : public a
{
public:
c();
void display();
};
c::c()
{
cout<<"c.............."<<endl;
}
void c::display()
{
cout<<"c::display"<<endl;
}
int main(void)
{
b* objb = new b;
c* objc = (c*)objb;
objc->display();
return 0;
}
执行结果:
a..............
b..............
b::display
我也这个时候肯定与晚绑定,多态有关,但还是不太明白,请哪位高手指点一下.谢谢!
发表于 2009-11-4 00:28:04 | 显示全部楼层 IP:江苏扬州
成员函数的调用都是通过指针完成的。

一般成员函数都是靠this来寻函数地址,然后调用它。
虚拟成员函数就是靠指向虚表的指针来找到虚拟函数的地址,然后调用它。


指针类型也可以看做是一种类型。
c* objc = (c*)objb;
objb代表的就是一个地址值。

我们看成objc->this==objb->this; //虽然这样写编译出错,我们只是假想一下。
但是不同型别的对象的this的值相同那又如何?

普通成员函数的函数地址是在声明时就相当于已经确定地址了。(当然,这个地址不是对象内存区内)
所以会根据不同对象类型的this得到正确的函数地址。

至于虚拟指针,对于继承关系的类来说,他们都有虚拟表,由于虚拟函数重写,回在重写的类里为自己重写的同名的函数赋予另外一个地址。

---------------------------------------------
现在脑子有点乱,估计说错了几句话,本来打算不说,免得误导人。
哎,就当是抛砖引玉吧。
回复

使用道具 举报

发表于 2009-11-4 00:28:06 | 显示全部楼层 IP:江苏扬州
以下是引用wfpb在2006-10-9 21:45:30的发言:
成员函数的调用都是通过指针完成的。

一般成员函数都是靠this来寻函数地址,然后调用它。
虚拟成员函数就是靠指向虚表的指针来找到虚拟函数的地址,然后调用它。


指针类型也可以看做是一种类型。
c* objc = (c*)objb;
objb代表的就是一个地址值。

我们看成objc->this==objb->this; //虽然这样写编译出错,我们只是假想一下。
但是不同型别的对象的this的值相同那又如何?

普通成员函数的函数地址是在声明时就相当于已经确定地址了。(当然,这个地址不是对象内存区内)
所以会根据不同对象类型的this得到正确的函数地址。

至于虚拟指针,对于继承关系的类来说,他们都有虚拟表,由于虚拟函数重写,回在重写的类里为自己重写的同名的函数赋予另外一个地址。

---------------------------------------------
现在脑子有点乱,估计说错了几句话,本来打算不说,免得误导人。
哎,就当是抛砖引玉吧。
老实说,我没看懂,可能我太笨了吧
回复

使用道具 举报

发表于 2009-11-4 00:28:07 | 显示全部楼层 IP:江苏扬州
我也不是很明白,哪个明白的能再给解释解释呀
回复

使用道具 举报

发表于 2009-11-4 00:28:08 | 显示全部楼层 IP:江苏扬州
说实在的
(我没有编译器)
你第一个得这个结果是非常偶然的,也是非常危险的
偶然与B与C的内存结构一样,尽管它们名字不一样
第一个没有虚拟,所以编译器编译时根本不看 *C到底是个什么东西
因为编译器知道*C所指内容的内存结构,所以直接就用C的地址(此时是*B的首地址)
+偏移量来寻找DISPLAY,而B与 C的内存又很偶然,所以,巧合的能找到DISPLAY
第二个有了虚拟,编译器在编译到这里时,不会轻易作决定,需要迟后联编,所以
这时才真正在运行时看*C的所指的内容到底是什么,然后就出现那个结果
回复

使用道具 举报

发表于 2009-11-4 00:28:09 | 显示全部楼层 IP:江苏扬州
首先谢谢上面给我答复的, thank you very much!

我想这不是偶然,请看下面情况:

#include <iostream>
using namespace std;
class a
{
public:
void display();
};
void a::display()
{
cout<<"a::display"<<endl;
}

class b : public a
{
public:
void display();
};
void b::display()
{
cout<<"b::display"<<endl;
}

class c : public a
{
public:
void display();
void show();
private:
int i;
};
void c::display()
{
i = 10;
cout<<"c::display"<<endl;
}
void c::show()
{
cout<<"c::show()"<<endl;
cout<<i<<endl;
}
int main(void)
{
b* objb = new b;
c* objc = (c*)objb;
objc->display();
objc->show();
return 0;
}

我在 c 类中增加了一个函数与一个私有的成员变量,而在进行 c* objc = (c*)objb 后,这个私有变量也就变成可用的了.

我觉得这个问题值得深究哟!呵呵
回复

使用道具 举报

发表于 2009-11-4 00:28:10 | 显示全部楼层 IP:江苏扬州
所以直接就用C的地址(此时是*B的首地址)
+偏移量来寻找DISPLAY


我的理解不是这样。
--------------------------------------------------
函数是靠地址调用的。

成员函数的地址是什么规则我也不太清楚。但是似乎与普通地址不同。


程序代码:

class A
{
public:
void display(){cout<<"A"<<endl;}
};

class B:public A
{
public:
void display(){cout<<"B"<<endl;}
};

class C:public A
{
int i;
public:
void display(){i=10;cout<<"C"<<endl;}
void show()
{
cout<<"Show:"<<i<<endl;
}
};


typedef void (B::*b_Func)();

void f(){}

typedef void (*FC)();

int main(int argc, char* argv[])
{
B b1,b2,b3,b4;
B b_ARR[4]={b1,b2,b3,b4};
b_Func b_FCArr[4]={b1.display,b2.display,b3.display,b4.display};
for(int i=0;i<4;i++)
{
cout<<b_FCArr[i]<<endl;
}

FC pFc=f;
cout<<pFc<<endl;


return 0;
}
结果输出的b_FCArr[i]都是1,而pFc却是一个地址值。


所以我认为,应该不会是一个偏移。
回复

使用道具 举报

发表于 2009-11-4 00:28:11 | 显示全部楼层 IP:江苏扬州
恩,今早特意赶来,感觉第一个的一半说的不对,用偏移不对。用符号表
麻烦大家看看,OBJC与OBJB的所指地址
我这没有,我也感觉很奇怪
可能一个解释,c* objc = (c*)objb
OBJC吞了OBJB的后面的地址
也就是越界操作。?
回复

使用道具 举报

发表于 2009-11-4 00:28:12 | 显示全部楼层 IP:江苏扬州
objb和objc我没试,但是所指地址肯定相同啊
回复

使用道具 举报

发表于 2009-11-4 00:28:14 | 显示全部楼层 IP:江苏扬州
我估计这和类型转换有着莫大的关系,应该是在进行类型转换的时候进运行了某种机制,但苦于现在一直没有找到相应的资料呀
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏ICP备08020429号 )

GMT+8, 2024-9-30 21:24 , Processed in 0.211703 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表