一个简单的C++问题请教

charlyisme 2002-07-13 05:53:55
一个简单的C++问题请教
编译器BC3.1
程序如下
#include "iostream.h"

class A
{public:
A() {cout<<"A create"<<endl;}
~A() {cout<<"A delete"<<endl;}
void afunc() {cout<<"Afunc run"<<endl;}
};

class B:public A
{public:
B() {cout<<"B create"<<endl;}
~B() {cout<<"B delete"<<endl;}
void bfunc() {cout<<"bfunc run"<<endl;}
};

void Test(B* b)
{b->bfunc();}

void main()
{A* a=new A;//1)A* a;
Test((B*)a);
……
}
运行时会显示:
A create
bfunc run
如果将A* a=new a;换成A*a(不申请内存),那么运行时会显示
bfunc run

问题:
1)为什么一个指向A的指针会有bfunc这个成员函数,Test((B*)a)这个强制转换到底做了什么工作?
2)如果将A* a=new a;换成A*a为什么运行时仍会显示bfunc run?根本没有申请内存那么bfunc这个函数是放在什么地方的?
请问哪位大侠详细给我讲讲,谢谢!
...全文
95 38 打赏 收藏 转发到动态 举报
写回复
用AI写文章
38 条回复
切换为时间正序
请发表友善的回复…
发表回复
ilovett 2002-07-19
  • 打赏
  • 举报
回复
once168(once168) 讲得还不错,大家可以看一看!
ilovett 2002-07-19
  • 打赏
  • 举报
回复
once168(once168) 的回答很详细,不错!
once168 2002-07-19
  • 打赏
  • 举报
回复
除了this_Call,BC中引以为荣的是FAST_CALL,FAST call的this指针基本相同只是传入的前两个参数用寄存器罢了
实际是VC也可设置为fast call(只不过不是默认罢了)
once168 2002-07-19
  • 打赏
  • 举报
回复
大家讲了这么多有不就是关于this指针的解释
以下是我的个人观点
1.编译器在调用类对像是会用ECX寄存器存放this指针(对于ThisCALL调用协定解释)
即所有的成员函数引用自身成员变量时都有一个this指针的偏移量,所以对像中就有类的概念,而成员函数(虚

函数除外)则仅仅是一个函数,当这个函数不用this指针时(如前面的程序),this指针传给成员函数与不传给

成员函数是一样的(即函数与写成全局函数执行结构是一样的),但当成员函数有引用自生成成员变量时,就要

能过this指针来计算成员变量,因为传入了错误的this指针那样将会出错
2。类型转换的问题
先说派生的原理:
派生是将父类成为子类的一个成员的,基类与在成员变量之前开始的(即第一基类与子类this指针相同)
如下面A类也是从B类派生的
class A
{
class B//A中生成一个类B
{

};
}
////////////////////////////
这就产生了类型转换的问题,下面分种情况分别列出
如下:
第一种情况:
class A
{
};
class B:(A与B不相关)
{
}或
class B:public C , A(A不是B的第一基类)
{
}
如果是这种情况的话将A对像指针转换成B将不安全,因为A、B关于this指针的传入偏移量是不对的

第二种情况:
class A
{
};
class B:public A, <c>(A是B的第一基类)
{
}
如果将B对像转换成A对像将是安全的因为A与B有相同的偏移地址

注:将B强型转换成C也是安全的(这时主要是编译器的功劳,因为编译器在类型转换中用static_cast进行类型

转换,如果成功就用static_cast返回的指针---所以编译器建议用static_cast进行类型转换,这样对于上面第

一种情况会报错

第三种情况:
class A
{
};
class B:public A, <c>(A是B的第一基类)
{
}
如果将A对像转换成B对像指针将可能成功可能不成功(这里我不用“安全”----即然不成功肯定是不安全)
因为持有A指针的对像有可能是B对像,也有可能是A对像或A的其它派生对像

3。类(确切的说应是域名--name space)的作用
类的作用有二:
1。告诉编译器这是要有this指针的
2。产生一个域,在域外将加在域名才能找到成员(即在编译时产生类的概念)----大家都知道静态函数的调用

方式,这里我再举一个类域的使用:
class A
{
public:
enum tagLorR{LEFT=0,RIGHT};
tagLorR fun(){m_t=RIGHT;return LEFT;};//这个谁都知道
tagLorR m_t;
}
如果你想在类的外面给m_t付值,如果不准用强性类型转换的话就只用域
即Obj.m_t=A::LEFT;
feahoo 2002-07-19
  • 打赏
  • 举报
回复
应该是B类中发生了拷贝构造吧。
ilovett 2002-07-19
  • 打赏
  • 举报
回复
up
demo_zcl 2002-07-18
  • 打赏
  • 举报
回复
UP
snowrain 2002-07-18
  • 打赏
  • 举报
回复
希望哪位大侠能给一个比较清楚的答案。
前面的各种意见已经把我弄糊涂了。
ilovett 2002-07-17
  • 打赏
  • 举报
回复
up
GoogleGeek 2002-07-16
  • 打赏
  • 举报
回复
To:rockhard(探索中...)
I have tested this programme in the Windows2000 Server,once you usethe variable that is only belong to the class B,the computer just throws a exception of violate access memory!
GoogleGeek 2002-07-16
  • 打赏
  • 举报
回复
To:charlyisme(John) :
为什么一个指向A的指针会有bfunc这个成员函数?
-----------------------------------------------
你怎么还认为类的成员函数就一定属于类的作用域呢?
类的成员函数在编译器眼里是和一般的全局函数没有什么多大的区别!只是在函数的调用上有特殊的语法要求而已!
指针的作用域内怎么会有函数呢?如果有的话,用指针的4个字节长度的内存空间如何能够表示多余的函数的地址呢?
ilovett 2002-07-16
  • 打赏
  • 举报
回复
???
ilovett 2002-07-15
  • 打赏
  • 举报
回复
呵呵,看糊涂了!不知道谁是对的。
ilovett 2002-07-15
  • 打赏
  • 举报
回复
gz
ilovett 2002-07-15
  • 打赏
  • 举报
回复
再up一下
ilovett 2002-07-15
  • 打赏
  • 举报
回复
up
kicku 2002-07-15
  • 打赏
  • 举报
回复
>我的OS是win2000 professional。在server下应该也是可以的,你可以试试。
>但象楼主那样:如果将A* a=new a;换成A*a(不申请内存),那么运行时产生访问错误。

你没有出访问错误不代表你没有访问到不正确的内存.....
polosheng 2002-07-14
  • 打赏
  • 举报
回复
我记得在vc6里象这样的强制转换是不允许的
GoogleGeek 2002-07-14
  • 打赏
  • 举报
回复
To: zf925(天下哪来那么多高手)
我的意思是并不是说编译器生成了类的对象,只是说在编译器的内在要求中需要一个对象的存在,但是那个对象到底真正的存在与否,其实编译器并不知道,也不需要知道!(只要你调用的时候不违反使用规则!)
实际上你所说的使用char * a;进行参数传递的函数调用!这未尝不可,只要他是个地址值即可,因为这样通过强制类型转换决可完成函数的调用!
例如下面的调用:
main()
{
.......
char *a;
double *fd;
double d;
void *v;
Test((B*)a);
Test((B*)fd);
Test((B*)&d);
Test((B*)v);
......
}
只要传递进去的是一个地址即可!但是编译器将该地址当作类B的实例的this指针!
zf925 2002-07-14
  • 打赏
  • 举报
回复
希望大家看到下面的程序不会大吃一惊:


#include "iostream.h"

class A
{public:
A() {cout<<"A create"<<endl;}
~A() {cout<<"A delete"<<endl;}
void afunc() {cout<<"Afunc run"<<endl;}
};

class B:public A
{public:
B() {cout<<"B create"<<endl;}
~B() {cout<<"B delete"<<endl;}
void bfunc() {cout<<"bfunc run"<<endl;}
};

void Test(B* b)
{b->bfunc();}

void main()
{
//A* a=new A;//1)A* a;
char *a;
Test((B*)a);
}


我不同意psusong(我心飞扬)的说法,其实(B*)a转换的只是指针
以上根本就没有生成类的对象,或者说生成了一个临时的对象,
与楼主的情况一样!!!!!!!!!!!!!!
加载更多回复(18)

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

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