a * pa = new a;b * pb = (b*)pa;pb->pintf();//B::printf 为什么

wonenggaoruanjianbu 2010-01-02 08:23:46

#include <iostream>
using namespace std;
class a
{
public:
void pintf(void)
{
cout<<"A:pintf"<<endl;
}
};
class b:public a
{
public:
void pintf(void)
{
cout<<"B:pintf"<<endl;
}
};
class c:public a
{
public:
void pintf(void)
{
cout<<"C:pintf"<<endl;
}
};
int main(int argc,char *argv[])
{
a * pa = new a;
b * pb = (b*)pa;
pb->pintf();//B::printf pb指向的实际模型对象为基类(a类), 怎么能访问到派生类(b类)对象的成员呢
}
...全文
718 35 打赏 收藏 转发到动态 举报
写回复
用AI写文章
35 条回复
切换为时间正序
请发表友善的回复…
发表回复
yunzhuabc 2010-09-15
  • 打赏
  • 举报
回复
#include<iostream>
using namespace std;

class A
{
public:
virtual void f() {cout<<"a"<<endl;}
};

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

int main()
{
A *pa=new A();

B* pb=(B*)pa;
pb->f();
return 0;
}

为什么A中的f函数加上virtual,输出为a;否则为b
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 wind__fantasy 的回复:]
回27楼的,pb为NULL时表示的是pb不指向任何对象,注意我说的是pb无论指向哪个对象,所以pb是指向一个特定对象的,当然你如果把NULL也当成一个对象的话,那我把那句话改成无论pb指向哪个非NULL对象,pb的类型由于在编译期已经确定为b*,因此调用b:printf。(手机上回帖不方便啊)
[/Quote]

手机上回帖不方便,呵呵,谢谢热心回帖!
guoliang258 2010-01-03
  • 打赏
  • 举报
回复
基类语句被隐藏了
msdn2009_2010 2010-01-03
  • 打赏
  • 举报
回复
给个例子,LZ研究下:

class a
{
public:
int aa;
public:
a(){aa=2;}
void pintf(void)
{
cout <<"A:pintf"<<endl; //这里没有使用aa,printf函数在定义了类a后,建立类a对象前就存在于内存代码段了
}

};
int main(int argc ,char *argv[])
{
b * pb = NULL;
pb->pintf()//正常输出,
}




class a
{
public:
int aa;
public:
a(){aa=2;}
void pintf(void)
{
cout <<"A:pintf"<<aa<<endl; //这里使用aa,而变量aa在定义了a类对象前并没有在内存中开辟空间。
}

};
int main(int argc ,char *argv[])
{
b * pb = NULL ;
pb->pintf()// 运行出错,将b *pb;改为b*pb =new b;就好。
}


qq29992579 2010-01-03
  • 打赏
  • 举报
回复
你的原内存中划分出来存放第一个对象a的空间是被覆盖了

a * pa = new a; 在内存中划分出一块存a类型储单元 再划出一块指针类型的存储空间pa用来存储刚刚划分分的那个a类型的 存储空间的首地址

b * pb = (b*)pa; 这一句意思是在内存中划分出一块b类型的存储空间 它的首地址 和前一个a的首地址相同 所以b会把原来a给覆盖掉
Wind__Fantasy 2010-01-03
  • 打赏
  • 举报
回复
回27楼的,pb为NULL时表示的是pb不指向任何对象,注意我说的是pb无论指向哪个对象,所以pb是指向一个特定对象的,当然你如果把NULL也当成一个对象的话,那我把那句话改成无论pb指向哪个非NULL对象,pb的类型由于在编译期已经确定为b*,因此调用b:printf。(手机上回帖不方便啊)
msdn2009_2010 2010-01-03
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 wonenggaoruanjianbu 的回复:]
引用 23 楼 milkylove 的回复:
因为不是虚函数,所以调哪个函数在编译期就决定了。而调的函数没有使用到类中的数据,所以没出错。

你说的很对,我验证过。

使用到类中数据出错,觉得好理解。我理解是  a * pa = new a;
    b * pb = (b*)pa;//
    pb->pintf();//此时pb指向a类对象。想使用b类中的数据成员,当然出错。(这样理解对吗)

但是为什么调的函数printf没有使用到b类中的数据成员就Ok呢?虽然没使用到b类的数据成员,但是

pb->pintf();//这里访问的是b类的函数成员啊,函数成员也是b类的成员嘛,这样就是使用指向a类对象

的指针访问到了b类对象的函数成员了,岂不是很。。。(就是这点不明白)

[/Quote]

LZ是没有理解类属性和对象属性的区别。

a * pa = new a;
b * pb = (b*)pa;//pb实际指向a对象,但其类型为b类类型
pb->pintf()//prinf作为b类的成员函数,为类中所有对象所有,在b类对象建立之前存在于内存代码段中,故可以成功调用。但printf中要正确调用了b类中的数据成员,则应定义b类对象

  • 打赏
  • 举报
回复
[Quote=引用 23 楼 milkylove 的回复:]
因为不是虚函数,所以调哪个函数在编译期就决定了。而调的函数没有使用到类中的数据,所以没出错。
[/Quote]
你说的很对,我验证过。

使用到类中数据出错,觉得好理解。我理解是 a * pa = new a;
b * pb = (b*)pa;//
pb->pintf();//此时pb指向a类对象。想使用b类中的数据成员,当然出错。(这样理解对吗)

但是为什么调的函数printf没有使用到b类中的数据成员就Ok呢?虽然没使用到b类的数据成员,但是

pb->pintf();//这里访问的是b类的函数成员啊,函数成员也是b类的成员嘛,这样就是使用指向a类对象

的指针访问到了b类对象的函数成员了,岂不是很。。。(就是这点不明白)
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 wind__fantasy 的回复:]
楼上正解,确切来说,由于基类a的print函数不是虚函数,因此不能实现多态,即程序不是运行期绑定而是编译期绑定,这样程序编译时已经确定pb的类型为b*,无论pb实际指向哪个对象,pb调用的都是b的成员函数,因为是编译期绑定
[/Quote]

你说的这个我基本可以理解,就是红色圈出有疑问:按你说法,是指针类型决定其调用内容,而不是由指针指向的实际对象决定了?

?那我定义一个空的类b的类型指针,来调用b类的成员,你觉得可行吗?
eg:
class b 
{
public:
int aa;
public:
b():aa(2){ }
void pintf(void)
{
cout <<"B:pintf" <<aa<<endl;
}
int main(int argc,char *argv[])
{

b * pb =NULL ;
pb->pintf();//运行出错
};

  • 打赏
  • 举报
回复
[Quote=引用 19 楼 thirteen07 的回复:]
其实把父类的指针强制类型转换再复制给子类型的指针,这种做法是不赞成的
就楼主的代码来说:
b * pb = (b*)pa;
在这一条赋值语句之后,pb指针指向的对象已经不是先前的a对象了,这时候pb指针对象指向的对象应该是b对像
[/Quote]

你说的和13楼说的相反,你认真看下13楼的,看看谁说的对?
GKatHere 2010-01-03
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 wind__fantasy 的回复:]
楼上正解,确切来说,由于基类a的print函数不是虚函数,因此不能实现多态,即程序不是运行期绑定而是编译期绑定,这样程序编译时已经确定pb的类型为b*,无论pb实际指向哪个对象,pb调用的都是b的成员函数,因为是编译期绑定
[/Quote]
UP
失落的凡凡 2010-01-03
  • 打赏
  • 举报
回复
pb->pintf();

因为是这样调用的,而pb又是一个B的指针,而且printf又不是虚函数,所以编译时就会判定调用B::printf();
失落的凡凡 2010-01-03
  • 打赏
  • 举报
回复
因为不是虚函数,所以调哪个函数在编译期就决定了。而调的函数没有使用到类中的数据,所以没出错。
taifeng123 2010-01-03
  • 打赏
  • 举报
回复
b * pb = (b*)pa;
强制类型转换了。跟继承没有任何关系。
Wind__Fantasy 2010-01-03
  • 打赏
  • 举报
回复
楼上正解,确切来说,由于基类a的print函数不是虚函数,因此不能实现多态,即程序不是运行期绑定而是编译期绑定,这样程序编译时已经确定pb的类型为b*,无论pb实际指向哪个对象,pb调用的都是b的成员函数,因为是编译期绑定
Meteor_Code 2010-01-02
  • 打赏
  • 举报
回复
a b的函数都是静态的(不是VIRTUAL的)
这样pb->printf调用的函数就永远是b的而无论你怎么的指针指项具体是谁,和继承方式没有关系
你可以测试如下代码
class a
{
public:
int aa;
public:
a(){aa=2;}
void pintf(void)
{
cout<<"A:pintf"<<aa<<endl;
}

};
class b
{
public:
int aa;
public:
b(){aa=1;}
void pintf(void)
{
cout<<"B:pintf"<<aa<<endl;
}

};
你就看出来了
你的pb->printf()(pb实际指到a的对象)会打出B:pintf2
明白就给分
Thirteen07 2010-01-02
  • 打赏
  • 举报
回复
其实把父类的指针强制类型转换再复制给子类型的指针,这种做法是不赞成的
就楼主的代码来说:
b * pb = (b*)pa;
在这一条赋值语句之后,pb指针指向的对象已经不是先前的a对象了,这时候pb指针对象指向的对象应该是b对象,b对象中的printf()函数覆盖了父类的printf()函数
下面的代码是在你的代码基础之上加了两个函数,验证了我的猜想
#include <iostream>
using namespace std;
class a
{
public:
void pintf(void)
{
cout<<"A:pintf"<<endl;
}
void printA(void)
{
cout<<"A"<<endl;
}
};
class b:public a
{
public:
void pintf(void)
{
cout<<"B:pintf"<<endl;
}
void printB(void)
{
cout<<"B:"<<endl;
}
};
class c:public a
{
public:
void pintf(void)
{
cout<<"C:pintf"<<endl;
}
};
int main(int argc,char *argv[])
{
a * pa = new a;
b * pb = (b*)pa;
pb->pintf();//B::printf pb指向的实际模型对象为基类(a类), 怎么能访问到派生类(b类)对象的成员呢
pb->printA();
pb->printB();
}



输出结果是:
B:printf;
A:
B:
beginnow 2010-01-02
  • 打赏
  • 举报
回复
强制转换的本质就是我不管你是一个什么类型,我就按照我的类型解释。只在语言层面有效。
  • 打赏
  • 举报
回复
自己顶下。希望能解开疑惑
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 mstlq 的回复:]
简化一下,给个原理一样的代码,供楼主参考……
这个问题跟虚函数无关,跟继承也无关,把斜枝蔓叶去掉之后,就是这个

C/C++ code
#include<iostream>usingnamespace std;class b
{public:void pintf(void)
{
cout<<"B:pintf"<<endl;
}
};int main(int argc,char*argv[])
{int*p=NULL;
b*pb=(b*)p;
pb->pintf();//B::printf}
[/Quote]

b*pb=(b*)p;//这里pb指向了b对象了吗?又没定义一个对象,怎么能凭空将空指针转化为一个实在的对象指针
加载更多回复(15)

64,648

社区成员

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

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