当前位置:首页技术教程第十一章:为何struct x1{struct x1 stX};无法通过编译,了解C++基本语言特性变量和类型
第十一章:为何struct x1{struct x1 stX};无法通过编译,了解C++基本语言特性变量和类型
°
  • 素材类型: 精品-素材
  • 上传时间:

  大家经常会碰到这样的问题:定义一个数据类型,而此数据类型又包含此数据类型的变量。通常做法应该是把数据类型中的变量定义为指针形式。例如定义一个二叉树的节点:

struct tagNode                     //二叉树节点
{
  ElemType data;                 //节点数据
  struct tagNode *pLeftNode;     //节点左孩子
  struct tagNode *pRightNode;    //节点右孩子
}

  上述二叉树节点定义是正确的,可以编译通过。但如果定义为下述对象形式,则无法编译通过:

struct tagNode                      //二叉树节点
{
  ElemType data;                  //节点数据
  struct tagNode LeftNode;        //节点左孩子
  struct tagNode RightNode;       //节点右孩子
} 

  然而上述对象形式的二叉树节点为何不能编译通过,而采用指针形式的二叉树节点可以编译通过呢?
  答案是 C/C++采用静态编译模型。程序运行时,结构大小会在编译后确定。程序编LeftNode.LeftNode.LeftNode..-.这类错误也称为类和结构的递归定义错误。要正确编译,编译器必须知道一个结构所占用的空间大小。除此之外还有一个逻辑方面的问题,在这种情况下,想想可以有LeftNode.LeftNode.LeftNode.LeftNode.
  如果采用指针形式,指针的大小与机器的字长有关,不管是什么类型,编译后指针的大小总是确定的,所以这种情况下不需要知道结构 struct tagNode 的确切定义。例如,在32 位字长的 CPU 中,指针的长度为 4 字节。所以,如果采用指针的形式,structtagNode的大小在其编译后即可确定,为sizeof(int)+4+4.对于对象形式的 struct tagNode定义,其长度在编译后是无法确定的。
  注意:
  (1) 在Visual studio 2010编译器中,错误C2460代表这种递归定义错误,编译提示:”identifier1″:使用正在定义的”identifier2″,将类或结构(identifier2)声明为其本身的成员(identifier1),不允许类和结构的递归定义。
  (2) 在编程过程中,禁止类和结构的递归定义,以防产生奇怪的编译错误。现在,我们继续讨论类递归定义的经典案例一两个类相互包含引用问题。这是所有 C++程序员都会碰到的经典递归定义案例。
案例:CA 类包含 CB类的实例,而 CB类也包含 CA 类的实例。代码实现如下:

//A.h实现CA类的定义
#include"B.h"
class CA
{
Public:
  intiData;        //定义int数据iData
  CB instanceB:    //定义CB 类实例instanceB
}
//B.h实现CB类的定义
#include"A.h"
class CB
{
public:
  int iData;      //定义int数据iData
  CAinstanceA;    //定义CA 类实例instanceA
}
int main()
{
  CAinstanceA;
  return 0;
}

  上述代码在VisualC 2010上无法编译通过,编译器会报出 C2460 错误。先分析一下代码存在的问题:

  ● CA类定义时使用CB类的定义,CB类定义时使用CA类的定义,递归定义。

  ● A.h包含了B.h,B.h 包含了A.h,也存在递归包含的问题。

  其实,无论是结构体的递归定义,还是类的递归定义,最后都归于一个问题C/C++采用静态编译模型。在程序运行时,结构或类大小都会在编译后确定。程序要正确编译,编译器必须知道一个结构或结构所占用的空间大小,否则编译器就会报出奇怪的编译错误,如C2460错误。

  最后,我们给出类或结构体递归定义的几个经典解法。这里以类为例,因为在C++中 struct也是class,class举例具有通用性。

  1.前向声明实现

//A.h实现CA类的定义

class CB;//前向声明CB类
class CA
{
public:
  Int iData;        //定义int数据iData
  CB*pinstanceB;  //定义 CB类的指针 pinstanceB
}

//B.h实现CB类的定义
#include "A.h"
class CB
{
public:
  Int iData;      //定义int数据iData
  CAinstanceA;  //定义 CA类实例instanceA
}
#include"B.h"
int main()
{
  CA instanceA;
  return 0;
}

  前向声明实现方式的主要实现原则:

  ●主函数只需要包含 B.h就可以,因为 B.h 中包含了A.h。

  ●A.h 中不需要包含 B.h,但要声明 class CB,在避免死循环的同时也成功引用了CB。

  ●包含class CB 声明,而没有包含头文件 B.h,这样只能声明 CB类型的指针,而不能实例化。

  2.friend声明实现

//A.h实现CA类的定义

class CA
{
public:
  friend class CB;    /友元类声明
  int iData;         //定义int数据iData
  CB *pinstanceB;  //定义CB类的指针 pinstanceB
}
//B.h实现CB类的定义
#include "A.h"
class CB
{
public:
  int iData;        //定义int数据iData
  CAinstanceA;    //定义 CA类实例 instanceA
}

#include"B.h"
int main()
{
  CA instanceA;
  return 0:
}

  friend友元声明实现说明:

  ● 主函数只需要包含B.h就可以,因为B.h中包含了A.h。

  ● A.h 中不需要包含B.h,但要声明class CB,在避免死循环的同时也成功引用了CB。

  ● class CA 包含class CB友元声明,而没有包含头文件 B.h,这样只能声明 CB类型的指针,而不能实例化。

  不论是前向声明实现还是friend友元实现,有一点是肯定的:即最多只能有一个类可以定义实例。同样头文件包含也是一件很麻烦的事情,再加上头文件中常常出现的宏定义,感觉各种宏定义的展开是非常耗时间的。类或结构体递归定义实现应遵循两个原则:

  (1) 如果可以不包含头文件,那就不要包含了。这时候前置声明可以解决问题。如果使用的仅仅是一个类的指针,没有使用这个类的具体对象(非指针),也没有访问到类的具体成员,那么前置声明就可以了。因为指针这一数据类型的大小是特定的,编译器可以获知。

  (2) 尽量在CPP文件中包含头文件,而非在头文件中。假设类A的一个成员是一个指向类B的指针,在类A的头文件中使用了类B的前置声明并编译成功,那么在A的实现中需要访问B的具体成员,因此需要包含头文件,那么我们应该在类A的实现部分(CPP文件)包含类 B的头文件而非声明部分。

  请谨记

  ● 类和结构体定义中禁止递归定义,以防产生奇怪的编译错误。如果两个类相互递归定义时,需考虑前向声明或friend友元实现。但无论通过何种方法实现,有一点是肯定的:即最多只能有一个类可以定义实例。

第十一章:为何struct x1{struct x1 stX};无法通过编译,了解C++基本语言特性变量和类型
温馨提示:

文章标题:第十一章:为何struct x1{struct x1 stX};无法通过编译,了解C++基本语言特性变量和类型

文章链接:https://www.xiciw.com/jsjc/1525.html

更新时间:2024年02月15日

本站大部分内容均收集于网络!若内容若侵犯到您的权益,请发送邮件至:xiciw#qq.com我们将第一时间处理!

资源所需价格并非资源售卖价格,是收集、整理、编辑详情以及本站运营的适当补贴,并且本站不提供任何免费技术支持。

                               

所有资源仅限于参考和学习,版权归原作者所有,更多请阅读菜鸟资源服务协议

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

给TA打赏
共{{data.count}}人
人已打赏
技术教程

第十章:枚举和一组预处理的#define 有何不同,了解C++基本语言特性变量和类型

2024-2-19 10:34:00

技术教程

第十二章:实现可变数组 struct{int namelen; char namestr[1];};,了解C++基本语言特性变量和类型

2024-2-21 11:04:00

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索