一个关于继承的问题。

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成员变量,但编译程序提示[成员变量初始化非法],怎么回事?小弟想了很久也想不透...

请大侠指点迷津,谢谢。
...全文
74 37 打赏 收藏 转发到动态 举报
AI 作业
写回复
用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)
"管家婆加密狗读写工具"是一款专门针对管家婆软件的辅助工具,旨在帮助用户进行加密狗的读取和写入操作。加密狗是一种硬件设备,通常用于软件的授权管理,确保只有拥有正确密钥的用户才能运行特定的软件。在IT行业中,这种技术被称为硬件锁或USB Dongle,它通过USB接口连接到计算机,存储了软件的许可证信息。 管家婆软件是一款广泛应用于中小企业财务管理、进销存管理、生产管理等领域的应用软件。它的不同版本可能需要不同的加密狗来验证用户的使用权。"适用于多种版本"表明这款工具兼容管家婆的多个产品版本,为用户提供了一站式的加密狗管理解决方案。 "已测试可用"意味着开发者或提供者已经对这个工具进行了实际的测试,确保它在实际环境中可以正常工作。这是非常重要的,因为它给用户带来了一定程度的信任,表明该工具在使用时不会出现严重的兼容性问题或功能失效。 "要有狗才能用哦"这一提示强调了加密狗是必不可少的,没有加密狗,这个读写工具将无法执行其功能。这意味着用户必须拥有合法的管家婆加密狗才能使用这个工具,否则将无法进行任何读写操作。 从压缩包中的文件名"管家婆写狗(R4ND全集)无壳版.exe"可以看出,这是一个针对管家婆软件的写狗工具,而且是"无壳版"。"无壳版"通常指的是软件去除了保护壳,即没有额外的防逆向工程措施,这可能使工具更易于理解和使用,但同时也可能让软件更容易被破解。"R4ND全集"可能表示这个工具包含了针对各种随机情况的全面支持,比如处理各种类型的加密狗或者各种数据写入需求。 "管家婆加密狗读写工具"是为了解决管家婆软件用户在加密狗管理上的问题而设计的,它具备广泛的版本兼容性,并经过了实际测试,确保功能的稳定性和可靠性。用户需要拥有管家婆的加密狗才能使用此工具进行读写操作,而提供的无壳版本可能方便了用户进行更深入的使用或调试。然而,使用无壳版工具也需谨慎,因为这可能会增加软件被非法利用的风险。
【PA1实验报告1】是关于计算机系统和软件开发的一个实验项目,主要涵盖了以下几个关键知识点: 1. **指令集架构**:实验的目标之一是熟悉指令集的架构。指令集是计算机处理器理解和执行的基本命令集合,它定义了处理器如何处理数据和控制硬件。在这里,虽然可以选择不同的指令集,如RISC-V或x86,但因为实现多个指令集的复杂性,实验选择了x86。x86架构是一种复杂的CISC(复杂指令集计算)架构,包含了大量的单条指令,可以执行多种操作。 2. **图灵机原理**:图灵机是一种理论计算模型,用于描述通用计算能力的极限。在实验中,探究图灵机的运行原理意味着理解其基本操作,包括如何读取和修改存储带上的符号,以及如何根据当前状态和读取的符号来改变状态和移动读写头。 3. **调试器的工作原理**:调试器是软件开发中的重要工具,用于检查和控制程序的执行。实验要求用代码模拟寄存器结构,实现调试器的基本功能。这包括设置断点、单步执行、查看寄存器和内存状态等。调试器的工作原理涉及追踪程序执行流程,中断执行以便分析,并能恢复执行以继续调试。 4. **寄存器结构模拟**:在x86架构中,有不同大小的寄存器,如32位、16位和8位寄存器。实验要求使用`union`结构来模拟这些寄存器,因为`union`可以在同一内存空间中存储不同大小的数据类型,从而反映x86寄存器的共用特性。例如,EAX寄存器可以视为AX、AH和AL的组合。 5. **NEMU模拟器**:NEMU是一个程序模拟器,它的目的是使其他程序能够在NEMU上运行,就像在真实的硬件上一样。实验中提到的`init_monitor()`函数是NEMU启动时调用的关键初始化函数,负责处理参数解析、日志文件初始化、镜像加载和ISA相关的初始化工作。`load_img()`函数用于加载客户程序的镜像,而`init_isa()`则涉及CPU状态的初始化,包括寄存器的设置。 6. **内存管理**:实验中提到了固定内存位置0x10000来加载客户镜像,以及抽象出来的API如`isa_default_img[]`和`isa_default_img_size`,这些API简化了镜像加载和内存管理。 7. **设备初始化**:`init_device()`函数用于初始化设备,这是模拟真实计算机环境的关键部分,因为模拟器需要模拟I/O设备以处理输入输出操作。 8. **断点和监视点**:实验还要求实现监视点功能,即断点。断点是调试中的一个关键元素,允许在特定代码行暂停程序执行,以便检查程序的状态。 这个实验全面地覆盖了计算机系统的基础知识,从底层的指令集到高级的调试技术,旨在加深学生对计算机系统运行机制的理解,并提供实践经验。通过这样的实验,学生不仅能够学习到理论知识,还能提升实际编程和解决问题的能力。
Nexus是Sonatype公司开发的一款强大的 Maven仓库管理器,它集成了Maven仓库代理、存储库聚合以及组件发布等功能,广泛应用于Java开发者的构建和部署流程中。标题"nexus-3.30.0-01-win64.zip"表示的是Nexus 3的30.0.0.1版本的Windows 64位安装包,这通常用于在Windows操作系统上搭建和管理本地或企业级的Maven仓库。 描述中提到可以从官方网站下载,这确保了软件来源的正规性与安全性。下载地址是https://help.sonatype.com/repomanager3/download/,这是Sonatype官方的帮助页面,用户可以在此获取最新版本的Nexus Repository Manager及其相关的文档和资源。 Nexus的核心功能包括: 1. **代理仓库**:Nexus可以作为Maven中央仓库的代理,减少对互联网的直接访问,提高开发效率。通过配置,它可以缓存远程仓库中的组件,本地团队可以快速获取所需依赖。 2. **存储库聚合**:允许用户将多个存储库(如Maven、npm、NuGet等)组合成一个逻辑组,便于管理和查找组件。 3. **组件发布**:开发者可以使用Nexus发布自己的软件组件,确保版本控制和权限管理。 4. **安全控制**:Nexus提供了精细的访问控制策略,可以限制不同用户或团队对不同存储库的访问权限。 5. **质量检查**:内置的构件验证功能可以检查上传的组件是否符合预设的规则,比如POM格式正确性、签名验证等。 6. **搜索与浏览**:Nexus提供图形界面,方便用户搜索、浏览和管理仓库中的组件。 7. **持续集成**:与CI/CD工具如Jenkins、GitLab CI/CD等集成,自动化构建和部署过程。 8. **版本管理**:支持SNAPSHOT版本的管理,方便进行开发阶段的版本迭代。 压缩包内的两个主要文件“sonatype-work”和“nexus-3.30.0-01”可能是Nexus的安装目录结构。"sonatype-work"通常包含Nexus运行时的数据和配置,如数据库连接信息、日志文件等;而"nexus-3.30.0-01"可能是Nexus的可执行程序和配置文件,用于启动和配置服务。 在安装和配置Nexus时,用户需要注意以下几点: - 安装路径应避免有空格和特殊字符,以防运行时出现问题。 - 配置文件通常位于“nexus-3.30.0-01/conf”目录下的“nexus.properties”,根据实际需求进行修改。 - 启动Nexus通常需要指定JAVA_HOME环境变量,确保使用的是兼容的Java版本。 - 需要创建并配置至少一个仓库,如Maven公共仓库的代理,以便开始使用。 - 对于生产环境,应考虑设置备份策略,防止数据丢失。 Nexus作为一款强大的软件仓库管理工具,对于Java开发者和企业来说,是构建高效、安全的软件供应链的重要组成部分。通过正确配置和使用,能够大大提高软件开发和发布的效率,同时保障组件的质量和安全性。

70,023

社区成员

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

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