派生类指针指向基类指针问题!

houzhenghui123 2010-10-27 09:24:36
输出的结果是:
In class A
In class B
代码贴上:
#include "iostream.h"
class A
{
public :
void print()
{
cout<<"In class A\n";
}
};
class B:public A
{
public:
void print()
{
cout<<"In class B\n";
}
};
int main(void)
{
A a;
B b;
A *pa=&b;//基类指针pa指向派生类的对象b,只截取b中的一部分,这个可以理解
B *pb=(B*)&a;//派生类指针pb指向基类对象a,
pa->print();
pb->print();//为什么打印的是“In class B”?,而不是“In class A”
return 0;
}

问题:
B *pb=(B*)&a;//派生类指针pb指向基类对象a,
pb->print();//为什么打印的是“In class B”?,而不是“In class A”
这两句代码,到底内部发生了什么?

PS:再次补充下,是派生类指针,指向基类的对象!这种写法到底有什么现实的意义!
着中解释下pb->print();//为什么打印的是“In class B”?,而不是“In class A”?






...全文
246 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
无尽大海 2010-10-28
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 houzhenghui123 的回复:]
引用 5 楼 we_sky2008 的回复:
非虚函数调用时静态解析的,只根据调用者的类型来查找函数
因为pb的类型是B *,所以对于pb->print();调用,编译器直接在B的域中查找函数print
因为B中存在print实例,所以调用的是B类的print实例

那么pb=(B*)&a;怎么解释了?
这句代码,到底有什么用了?
[/Quote]
这是不安全的,这种强制转换得到的对象只会含有基类自己的部分,而派生类的部分就没有了!如果派生类中另外声明了指针,常量等成员变量等,这一切都是未赋值的,指针不知道指向哪里了!
lixing01 2010-10-28
  • 打赏
  • 举报
回复
B(){ bb = 55;bb = 'e';} //应该是 aa = 55吧
void print1(int i)
{
cout<<"In class B\n";
cout << i << endl;
cout << aa << endl;//随机数
cout << bb << endl;//怎么就是输出4?
//不安全的指针类型转换和使用,指向都是无效的地址,单步调式看一下内存数据就知道了
}

//还是把类继承相关的知识看看吧,基础性的先弄透彻,否则学习效率很低
lixing01 2010-10-28
  • 打赏
  • 举报
回复
/******************************************************************************
* B *pb=(B*)&a;//派生类指针pb指向基类对象a,
* pb->print();//为什么打印的是“In class B”?,而不是“In class A”
* 这两句代码,到底内部发生了什么?
* PS:再次补充下,是派生类指针,指向基类的对象!这种写法到底有什么现实的意义!
* 着中解释下pb->print();//为什么打印的是“In class B”?,而不是“In class A”?
******************************************************************************/

B *pb=(B*)&a;//基类对象的地址强制转换为派生类地址并赋值给派生类指针,这是不安全的,如果你没有强制转换编译是不能通过的.类型强制转换的安全性必须由程序员来负责.
pb->print();//强制转换后,自然就调用了派生类的方法.假如该函数使用到了派生类特有的数据,必将报错,因为该地址指向的对象为基类对象,并不存在该数据,这也能帮助你理解为什么这种转换不安全

A *pa=&b;
pa->print(); //派生类的地址赋给基类指针,继承的语法规则确保了这种行为是安全的,由于不是虚函数,所以将使用基类的方法,如果print定义为虚函数,则按照虚函数的规则确定最终调用的函数版本(虚函数的动态绑定)

派生类对象地址赋给基类指针,然后通过基类指针调用方法,结合虚函数的特性,实现动态绑定,是有实际的使用意义的.一个比较有趣的比喻:
基类:人,虚函数:上厕所.
派生类:女人,男人.虚函数重定义:上女厕所,上男厕所.
动态绑定的规则,就能自动让男人和女人正确地上各自的厕所.

反过来,基类对象地址强制转换赋给派生类指针,根据继承规则,逻辑上无法确保安全,往往也没有实际的应用价值.
liutengfeigo 2010-10-27
  • 打赏
  • 举报
回复
难道又是未定义的行为,一切皆有可能?
liutengfeigo 2010-10-27
  • 打赏
  • 举报
回复

#include <iostream>
using namespace std;
class A
{
public :
void print(int i)
{
cout<<"In class A\n";
cout << i << endl;
}
private:
int aa;
};
class B:public A
{
public:
B(){ bb = 55;bb = 'e';}
void print1(int i)
{
cout<<"In class B\n";
cout << i << endl;
cout << aa << endl;//随机数
cout << bb << endl;//怎么就是输出4?
}
private:
int aa;
char bb;
};
int main(void)
{
A a;
B b;
A *pa=&b;//基类指针pa指向派生类的对象b,只截取b中的一部分,这个可以理解
B *pb=(B*)&a;//派生类指针pb指向基类对象a,
pa->print(5);
pb->print1(55);//为什么打印的是“In class B”?,而不是“In class A”
system("pause");
return 0;
}
liutengfeigo 2010-10-27
  • 打赏
  • 举报
回复

#include <iostream>
using namespace std;
class A
{
public :
void print(int i)
{
cout<<"In class A\n";
cout << i << endl;
}
private:
int aa;
};
class B:public A
{
public:
B(){ bb = 55;bb = 'e';}
void print(int i)
{
cout<<"In class B\n";
cout << i << endl;
cout << aa << endl;//随机数
cout << bb << endl;//怎么就是输出4?
}
private:
int aa;
char bb;
};
int main(void)
{
A a;
B b;
A *pa=&b;//基类指针pa指向派生类的对象b,只截取b中的一部分,这个可以理解
B *pb=(B*)&a;//派生类指针pb指向基类对象a,
pa->print(5);
pb->print(55);//为什么打印的是“In class B”?,而不是“In class A”
system("pause");
return 0;
}
houzhenghui123 2010-10-27
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 lthyxy 的回复:]
果然是个好方法。
等高手来回答,咱等着
[/Quote]vc6.0
無_1024 2010-10-27
  • 打赏
  • 举报
回复
派生类和基类可以同时存在相同名的成员函数
liutengfeigo 2010-10-27
  • 打赏
  • 举报
回复
果然是个好方法。
等高手来回答,咱等着
liutengfeigo 2010-10-27
  • 打赏
  • 举报
回复
什么编译器?
浮世尘雲 2010-10-27
  • 打赏
  • 举报
回复
你的语句本来就不合法,让一个派生类指针指向一个基类对象,这属于类型欺骗,很容易产生运行时期错误,

至于为什么调用到派生类的函数,就是因为编译器的静态绑定,楼上的说得很清楚了,至于说意义吗,正如我

前面所说,这种用法本身就是个错误,何来意义只有,明知道是一个基类对象,有怎么可能会用一个派生类

指针指向它,像你举的这个例子,如果print成员函数会访问到一个派生类的数据成员的话,那么后果将是

灾难性的,真正实现向下转换应该使用dynamic_cast转换符。
we_sky2008 2010-10-27
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 houzhenghui123 的回复:]
引用 5 楼 we_sky2008 的回复:
非虚函数调用时静态解析的,只根据调用者的类型来查找函数
因为pb的类型是B *,所以对于pb->print();调用,编译器直接在B的域中查找函数print
因为B中存在print实例,所以调用的是B类的print实例

那么pb=(B*)&a;怎么解释了?
这句代码,到底有什么用了?
[/Quote]
这种用法很危险的,并不是编译通过就有什么意义的,例如,在你的这个例子中:

#include "iostream.h"
class A
{
public :
void print()
{
cout<<"In class A\n";
}
};
class B:public A
{
public:
void print()
{
cout<<"In class B\n";
}
};

int main(void)
{
char ch = 'A';
B *pb = (B *)&ch;

pb->print();//这里照样能输出In class B,这里意义何在呢?

return 0;
}

houzhenghui123 2010-10-27
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 we_sky2008 的回复:]
非虚函数调用时静态解析的,只根据调用者的类型来查找函数
因为pb的类型是B *,所以对于pb->print();调用,编译器直接在B的域中查找函数print
因为B中存在print实例,所以调用的是B类的print实例
[/Quote]
那么pb=(B*)&a;怎么解释了?
这句代码,到底有什么用了?
浅行 2010-10-27
  • 打赏
  • 举报
回复
把print函数加上virtual变成一个虚函数,在试试看,你就明白了
we_sky2008 2010-10-27
  • 打赏
  • 举报
回复
非虚函数调用时静态解析的,只根据调用者的类型来查找函数
因为pb的类型是B *,所以对于pb->print();调用,编译器直接在B的域中查找函数print
因为B中存在print实例,所以调用的是B类的print实例
黑娃 2010-10-27
  • 打赏
  • 举报
回复
因为print不是虚函数,所以使用指针调用的时候不会发生运行时多台,而由编译时决定,即,并不是看指针所指的是基类还是派生类,而是取决于指针自己的类型是基类还是派生类
houzhenghui123 2010-10-27
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 graymole2010 的回复:]
void print()
不是虚函数,不支持多态了。
[/Quote]
不好意思,这个贴不讨论虚函数!
不好意思
GrayMole2010 2010-10-27
  • 打赏
  • 举报
回复
void print()
不是虚函数,不支持多态了。
houzhenghui123 2010-10-27
  • 打赏
  • 举报
回复

64,648

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧