| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1068 人关注过本帖
标题:[求助] 关于继承与转换
只看楼主 加入收藏
wuliang_227
Rank: 1
等 级:新手上路
帖 子:7
专家分:0
注 册:2006-8-17
收藏
 问题点数:0 回复次数:11 
[求助] 关于继承与转换

#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

我也这个时候肯定与晚绑定,多态有关,但还是不太明白,请哪位高手指点一下.谢谢!

搜索更多相关主题的帖子: 继承 
2006-10-09 20:08
wfpb
Rank: 6Rank: 6
等 级:贵宾
威 望:29
帖 子:2188
专家分:0
注 册:2006-4-2
收藏
得分:0 
成员函数的调用都是通过指针完成的。

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


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

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

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

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

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

[glow=255,red,2]wfpb的部落格[/glow] 学习成为生活的重要组成部分!
2006-10-09 21:45
我不是郭靖
Rank: 3Rank: 3
等 级:新手上路
威 望:6
帖 子:494
专家分:6
注 册:2006-10-4
收藏
得分:0 
以下是引用wfpb在2006-10-9 21:45:30的发言:
成员函数的调用都是通过指针完成的。

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


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

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

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

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

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

老实说,我没看懂,可能我太笨了吧


2006-10-10 14:29
wuliang_227
Rank: 1
等 级:新手上路
帖 子:7
专家分:0
注 册:2006-8-17
收藏
得分:0 
我也不是很明白,哪个明白的能再给解释解释呀

2006-10-10 18:09
song4
Rank: 7Rank: 7Rank: 7
等 级:贵宾
威 望:38
帖 子:1533
专家分:4
注 册:2006-3-25
收藏
得分:0 

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


嵌入式 ARM 单片机 驱动 RT操作系统 J2ME LINUX  Symbian C C++ 数据结构 JAVA Oracle 设计模式 软件工程 JSP
2006-10-10 20:43
wuliang_227
Rank: 1
等 级:新手上路
帖 子:7
专家分:0
注 册:2006-8-17
收藏
得分:0 

首先谢谢上面给我答复的, 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 后,这个私有变量也就变成可用的了.

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


2006-10-10 21:04
wfpb
Rank: 6Rank: 6
等 级:贵宾
威 望:29
帖 子:2188
专家分:0
注 册:2006-4-2
收藏
得分:0 
所以直接就用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却是一个地址值。

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

[glow=255,red,2]wfpb的部落格[/glow] 学习成为生活的重要组成部分!
2006-10-10 22:00
song4
Rank: 7Rank: 7Rank: 7
等 级:贵宾
威 望:38
帖 子:1533
专家分:4
注 册:2006-3-25
收藏
得分:0 

恩,今早特意赶来,感觉第一个的一半说的不对,用偏移不对。用符号表
麻烦大家看看,OBJC与OBJB的所指地址
我这没有,我也感觉很奇怪
可能一个解释,c* objc = (c*)objb
OBJC吞了OBJB的后面的地址
也就是越界操作。?


嵌入式 ARM 单片机 驱动 RT操作系统 J2ME LINUX  Symbian C C++ 数据结构 JAVA Oracle 设计模式 软件工程 JSP
2006-10-11 07:13
wfpb
Rank: 6Rank: 6
等 级:贵宾
威 望:29
帖 子:2188
专家分:0
注 册:2006-4-2
收藏
得分:0 
objb和objc我没试,但是所指地址肯定相同啊

[glow=255,red,2]wfpb的部落格[/glow] 学习成为生活的重要组成部分!
2006-10-11 07:29
wuliang_227
Rank: 1
等 级:新手上路
帖 子:7
专家分:0
注 册:2006-8-17
收藏
得分:0 
我估计这和类型转换有着莫大的关系,应该是在进行类型转换的时候进运行了某种机制,但苦于现在一直没有找到相应的资料呀

2006-10-11 19:16
快速回复:[求助] 关于继承与转换
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.035614 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved