设为首页收藏本站

新微赢技术网

 找回密码
 注册
搜索
热搜: 回贴
查看: 1189|回复: 9
打印 上一主题 下一主题

[求助] 关于继承与转换

[复制链接]
跳转到指定楼层
1#
发表于 2009-11-4 00:28:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#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
我也这个时候肯定与晚绑定,多态有关,但还是不太明白,请哪位高手指点一下.谢谢!
2#
发表于 2009-11-4 00:28:04 | 只看该作者
成员函数的调用都是通过指针完成的。

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


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

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

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

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

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

使用道具 举报

3#
发表于 2009-11-4 00:28:06 | 只看该作者
以下是引用wfpb在2006-10-9 21:45:30的发言:
成员函数的调用都是通过指针完成的。

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


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

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

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

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

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

使用道具 举报

4#
发表于 2009-11-4 00:28:07 | 只看该作者
我也不是很明白,哪个明白的能再给解释解释呀
回复 支持 反对

使用道具 举报

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

使用道具 举报

6#
发表于 2009-11-4 00:28:09 | 只看该作者
首先谢谢上面给我答复的, 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 后,这个私有变量也就变成可用的了.

我觉得这个问题值得深究哟!呵呵
回复 支持 反对

使用道具 举报

7#
发表于 2009-11-4 00:28:10 | 只看该作者
所以直接就用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却是一个地址值。


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

使用道具 举报

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

使用道具 举报

9#
发表于 2009-11-4 00:28:12 | 只看该作者
objb和objc我没试,但是所指地址肯定相同啊
回复 支持 反对

使用道具 举报

10#
发表于 2009-11-4 00:28:14 | 只看该作者
我估计这和类型转换有着莫大的关系,应该是在进行类型转换的时候进运行了某种机制,但苦于现在一直没有找到相应的资料呀
回复 支持 反对

使用道具 举报

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

本版积分规则

申请友链|小黑屋|最新主题|手机版|新微赢技术网 ( 苏ICP备08020429号 )  

GMT+8, 2024-11-19 02:40 , Processed in 0.119108 second(s), 9 queries , Gzip On, Memcache On.

Powered by xuexi

© 2001-2013 HaiAn.Com.Cn Inc. 寰耽

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