一个关于继承的问题。

sr388 2002-05-26 10:11:40
原程序很短,很简单,不会浪费你太多的时间,请先看看。

#include <iostream.h>

class xSize
{
public:
xSize():itsSize(0) {}
xSize(int size):itsSize(size) {}
~xSize(){}
virtual int GetSize() {return itsSize ;}
virtual void PrintError()
{ cout << "Size error. Received: " << itsSize << endl ; }

protected:
int itsSize ;
};


class xTooSmall : public xSize
{
public:
xTooSmall(int size):itsSize(size) {}
virtual void PrintError()
{
cout << "Too small! Received: " ;
cout << itsSize << endl ;
}

};


int main()
{
xTooSmall MyObject(5) ;
MyObject.PrintError() ;

return 0 ;

}

编译时,VC6提示:

error C2614: 'xTooSmall' : illegal member initialization: 'itsSize' is not a base or member
Error executing cl.exe.

test.obj - 1 error(s), 0 warning(s)

本意:使用xTooSmall MyObject(5)创建一个xTooSmall对象,当创建xTooSmall对象时,基类xSize的默认构造函数:xSize():itsSize(0) {} 将被调用,基类中的成员变量itsSize被初始化为0。接着,派生类构造函数: xTooSmall(int size):itsSize(size) {}被调用,将实参5赋给派生类的成员变量:itsSzie --> 这个成员变量是从基类xSize中继承的。逻辑上来说,程序应该是没什么问题,protected对派生类可见,那么xTooSmall将继承基类的itsSize成员变量,但编译程序提示[成员变量初始化非法],怎么回事?小弟想了很久也想不透...

请大侠指点迷津,谢谢。
...全文
59 37 打赏 收藏 转发到动态 举报
写回复
用AI写文章
37 条回复
切换为时间正序
请发表友善的回复…
发表回复
magicblue 2002-06-14
  • 打赏
  • 举报
回复
SystemAdministrator(没齿骆驼):

> 由于编译器将基类与派生类的数据按照派生时指定的虚或非虚式的派生安排在> 一起,所以构造函数将由基类->派生类的顺序执行。

请问怎么“安排”?

又一个“狂人”……
sr388 2002-06-12
  • 打赏
  • 举报
回复
对了,还是错了?

大汤姆狼怎么不说话了?

如果我错了,请给出正确答案
sr388 2002-06-10
  • 打赏
  • 举报
回复
To: lixiner(大汤姆狼)

>>本来不想说什么,但顶楼实在太狂妄了。
>>就请你不要查书,说说成员函数,虚拟函数
>>内存入口地址运行时如何得到。
>>说的对,我向你道歉
>>说的不对,你就向大家道歉!

获得成员函数的地址靠this指针

虚拟函数的地址保存在vtable中
  • 打赏
  • 举报
回复
事实胜于雄辩,问题的本末至此,我也不再想于这些基础的问题上浪费精力与时间了,只希望sr388(左手剑)严谨对待科学。
tubin 2002-06-06
  • 打赏
  • 举报
回复
谢谢分哟,这可是我的第一次得分,不过可怜才10分。
lixiner 2002-06-05
  • 打赏
  • 举报
回复
楼上的理解大部分都很正确,
比sr388(左手剑)强多了!
我是说他狂妄!
说白了类是对现实世界的抽象,
我举学生的例子是表明
想象生活中的实例
有利于了解类、对象
继承等等的概念!

lixiner 2002-06-05
  • 打赏
  • 举报
回复
将类的虚拟成员函数转换成结构中的虚函数指针。
----这句话就有问题,
实际上结构只存在虚拟函数跳转表指针
无论有多少个虚函数,只有一个虚拟跳转表!
用sizeof看看就知道了到底存在几个指针??
-----“学生是人”这句话的完整说明应该是“学生的属性是人”,
这是典型的 is a 的问题!
  • 打赏
  • 举报
回复
继续狂妄。
首先对C++的OOP原则作一些解释。OOP原则的关键在于对问题属性的描述,“学生是人”这句话的完整说明应该是“学生的属性是人”,也就是说,学生类的一个个体,属性既是学生,更是人,“学生”和“人”之间并不排斥。
由于C++类的概念只存在于编译器一层,所以,在编译后的执行代码内部,是看不到有类这种东西的。编译器将类的非虚成员函数转换成全局函数,将类的数据成员转换成结构,将类的虚拟成员函数转换成结构中的虚函数指针。其它部分的C++特性,多数都只存在于编译器的逻辑之中。
那么在编译后的代码中,基类的构造函数与派生类的函数将如何执行呢?由于编译器将基类与派生类的数据按照派生时指定的虚或非虚式的派生安排在一起,所以构造函数将由基类->派生类的顺序执行。这符合一个对象由初级到高级的生长过程。在派生类的构造函数中,也有可能依据基类的数据成员的状态初始化自己的数据成员。
类的析构函数的执行顺序则必须与构造函数成相反的顺序才能保证执行的正确性,为什么要这样,我不必解释。
如果还有疑问,可以做一试验,使用编译器将C++源码译成C源码,可以看到究竟。如果有哪本书里说了基类调子类,或者子类调基类这样的鬼话,还是不看的妙。
由于类在执行代码中并不存在,所以不存在如何获得执行地址的问题,只是虚函数从数据区查表获得,所以性能略有牺牲。
lixiner 2002-06-05
  • 打赏
  • 举报
回复
顶楼,你的错误本身就很愚蠢
人有名字,学生继承人
学生就有两个名字了?
有时候想想现实情况。

lixiner 2002-06-05
  • 打赏
  • 举报
回复
sr388(左手剑) 大汤姆狼,类成员函数、虚拟函数清楚得很!
只是在我的这个程序中用不着它们!

kof99th(小虫) :不会吧,如果对继承时的成员变量布局不是很清楚,又怎么回清楚虚拟函数呢?建议你看看inside the c++ object modal,对你很有用的。

本来不想说什么,但顶楼实在太狂妄了。
就请你不要查书,说说成员函数,虚拟函数
内存入口地址运行时如何得到。
说的对,我向你道歉
说的不对,你就向大家道歉!

  • 打赏
  • 举报
回复
你的分比你的人还贱,谁要啊。
基类的构造函数与派生类的构造函数的执行顺序由C++编译器决定,而C++编译器决定了它们由基类->派生类的顺序执行。如果哪本书里有关于基类构造调用派生类构造的鬼话,那不是书的作者疯了,就是你瞎了。
这么初级的原则,本来懒得跟你解释,不过看在救人一命胜造七层猪圈的份上(给你解释解释也算砌了几块砖吧),给你指点一二,有功夫的话,请多领悟设计方面的知识,另外,不要动不动就话里带粗,这样至少可以减少因为你的脑子的先天BUG而丢人现眼的机会。
sr388 2002-06-04
  • 打赏
  • 举报
回复
To SystemAdministrator(没齿骆驼):

你穷疯了是不?

又没正确回答我的问题,也没说出那本书对[派生类构造函数会调用基类构造函数]有描述,还想要分?

拜托,要分之前请先看看得分原则,别整天脑子里就想着分啊分的,你看看人家,回答得那么好,也没好意思开口要分,真不要脸!
sr388 2002-06-04
  • 打赏
  • 举报
回复
To magicblue(小飞侠):

我说过,谁要是告诉我在那本书里对[派生类构造函数会调用基类构造函数]这一细节有描述,我将给分。

小飞侠,得分!

哦,对了,我会记住你的忠告,谦虚一点。
sr388 2002-06-04
  • 打赏
  • 举报
回复
首先让我们来看一看tubin(tubin)所示例程的简化版本:

#include <iostream.h>

class xSize
{
public:
xSize()
{
int* pBaseClass ;
pBaseClass = &itsSize ;
cout << pBaseClass << endl ; // 输出基类的itsSize的地址
}

~xSize() {}

protected:
int itsSize ;
};


class xTooSmall : public xSize
{
public:
xTooSmall()
{
int* pDeriveClass ;
pDeriveClass = &itsSize ;
cout << pDeriveClass <<endl ; // 输出派生类itsSize的地址
}

~xTooSmall() {}


};


int main()
{
xTooSmall MyObject ;

return 0 ;

}

在我的电脑上运行的结果是:

0x0012FF7C
0X0012FF7C

这能说明什么呢?当然是派生类与基类共用同一份成员变量。

因为tubin(tubin)所示例程的清析性,给分!
sr388 2002-05-31
  • 打赏
  • 举报
回复
step_by_step(脚步):
创建派生类时,基类的构造函数是派生类的构造函数调用的吗?

在那本书里有讲述啊,说出来分全给你。
sr388 2002-05-31
  • 打赏
  • 举报
回复
JustinLee1998,你都没有对itsSize成员变量赋值,你的:

Myobj2.PrintSize2();

能输出什么?!!!

我不明白你加上这段代码有什么用!
xiexue888 2002-05-31
  • 打赏
  • 举报
回复
完全支持 SystemAdministrator(没齿骆驼) !!!
magicblue 2002-05-31
  • 打赏
  • 举报
回复
帖主:
谦虚一点没什么不好,我去年看过你回别人的帖子,说自己已经对C++有很深的了解,原话我忘了,反正口气很大...过这么久,好象你还是停留在中初级水平啊...
step_by_step 说的很对啊,你不会连这个都不知道吧,派生类的构造函数的扩展码会对基类的构造函数作调用(详见<Inside C++ Object Model>)
tubin 2002-05-31
  • 打赏
  • 举报
回复
#include <iostream.h>

class xSize
{
public:
xSize()
{int *p;
p=&itsSize;
cout<<p<<endl;//输出基类的itsSize的地址
}
~xSize() {}

protected:
int itsSize ;
};


class xTooSmall : public xSize
{
public:
xTooSmall() {}
~xTooSmall() {}

void SetSize(int size1, int size2)
{
xSize::itsSize = size1 ;
itsSize = size2 ;
}

void PrintSize() const
{
cout << "xTooSmall::itsSize: " << &itsSize << endl ; //输出派生的itsSize地址
}

};


int main()
{
xTooSmall MyObject ;
MyObject.SetSize(10, 10000) ;
MyObject.PrintSize() ;

return 0 ;

}
在VC6下通过
结果基类和派生类输出的值完全一样
能否说明是共用了一份itsSize?
望各位赐教!
  • 打赏
  • 举报
回复
楼上(左手剑)你的观点还是有误:
在基类与派生类中,构造函数与析构函数的执行次序就如同洋葱的生长与剥皮过程一样,构造函数的执行是长的过程(由里至表),析构函数的执行是剥的过程(由外至内)。
守信的话,分拿来。
加载更多回复(17)

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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