热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

两个类相互引用的解决方法

1问题提出最近在编写“斗地主”游戏,在程序中有一个“CDealer”类用来实现发牌等等功能,还有一个“CPoker”类,用来表示扑克牌。在CDealer类中包含了一个CPoker类指针的成员变量,而

1 问题提出

最近在编写“斗地主”游戏,在程序中有一个“CDealer”类用来实现发牌等等功能,还有一个“CPoker”类,用来表示扑克牌。在CDealer类中包含了一个CPoker类指针的成员变量,而在CPoker类中也包含了一个CDealer类指针的成员变量,如下所示:

//CPoker类头文件

#pragmaonce

#include"Dealer.h"

class CPoker

{

public:

    CPoker(void);

    ~CPoker(void);

private:

    CDealer *m_pDealer;

};

//CDealer类的头文件

#pragmaonce

#include"Poker.h"

class CDealer

{

public:

    CDealer(void);

    ~CDealer(void);

private:

    CPoker *m_pPoker;

};

程序编译时,错误提示为

poker.h(10) :error C2143: 语法错误: 缺少“;”(在“*”的前面)

poker.h(10) :error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int

2 问题分析

因为在程序中首先包含的是Dealer.h,所以Dealer.h头文件首先被编译。如图3-1所示。在CDealer类的头文件中,第1步执行了#pragma once之后就进入到第2步,即Poker.h头文件中。在Poker.h头文件中进行第3步,执行#pragma once,之后进入到第4步,也就是Dealer.h中,由于Dealer.h中包含#pragma once,并且此时已经被编译,所以第4步中的#include “Dealer.h”实际上没有执行,继续进行到Poker.h的第5步,定义CDealer类的指针,此时CDealer类实际上还没有定义,因此编译时回报错。

3 问题解决

3.1 类的前向声明

从2中分析可以看到,报错的主要原因是CDealer类没有定义。可以使用类的前向声明(forwarddeclaration)的方式解决这个问题。如

class CDealer;


图3-1 头文件执行流程

在CPoker类定义中映入了类类型CDealer。在类声明之后而定义之前,类CDealer是一个不完全类型(incompetetype),即已知CDealer是一个类,但不知道包含哪些成员,所以使用类的前向定义后,只能声明该类的指针,而不是该类的对象。

同理,在Dealer.h中加入CPoker类的前向声明。

classCPoker;

3.2 将包含头文件的代码放到执行文件

尽量将包含头文件的语句放到执行文件(.cpp文件)中而不是在头文件中(.h文件)。因此,接下来将#include“Poker.h”语句放到Dealer.cpp文件中,而将#include“Dealer.h”语句放到Poker.cpp文件中。

4 小结

对于两个类间相互引用引发的编译错误,可以使用类前向声明的方式解决。类前向声明是一个不完整类型,只能使用其指针。尽量将包含头文件的代码放在cpp执行文件中,而不是h头文件中。


推荐阅读
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 本文深入探讨 MyBatis 中动态 SQL 的使用方法,包括 if/where、trim 自定义字符串截取规则、choose 分支选择、封装查询和修改条件的 where/set 标签、批量处理的 foreach 标签以及内置参数和 bind 的用法。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 本文深入探讨了Linux系统中网卡绑定(bonding)的七种工作模式。网卡绑定技术通过将多个物理网卡组合成一个逻辑网卡,实现网络冗余、带宽聚合和负载均衡,在生产环境中广泛应用。文章详细介绍了每种模式的特点、适用场景及配置方法。 ... [详细]
  • 本文详细介绍了macOS系统的核心组件,包括如何管理其安全特性——系统完整性保护(SIP),并探讨了不同版本的更新亮点。对于使用macOS系统的用户来说,了解这些信息有助于更好地管理和优化系统性能。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • C++构造函数与初始化列表详解
    本文深入探讨了C++中构造函数的初始化列表,包括赋值与初始化的区别、初始化列表的使用规则、静态成员初始化等内容。通过实例和调试证明,详细解释了初始化列表在对象创建时的重要性。 ... [详细]
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 数据管理权威指南:《DAMA-DMBOK2 数据管理知识体系》
    本书提供了全面的数据管理职能、术语和最佳实践方法的标准行业解释,构建了数据管理的总体框架,为数据管理的发展奠定了坚实的理论基础。适合各类数据管理专业人士和相关领域的从业人员。 ... [详细]
  • CentOS7源码编译安装MySQL5.6
    2019独角兽企业重金招聘Python工程师标准一、先在cmake官网下个最新的cmake源码包cmake官网:https:www.cmake.org如此时最新 ... [详细]
  • 解决PHP与MySQL连接时出现500错误的方法
    本文详细探讨了当使用PHP连接MySQL数据库时遇到500内部服务器错误的多种解决方案,提供了详尽的操作步骤和专业建议。无论是初学者还是有经验的开发者,都能从中受益。 ... [详细]
  • CMake跨平台开发实践
    本文介绍如何使用CMake支持不同平台的代码编译。通过一个简单的示例,我们将展示如何编写CMakeLists.txt以适应Linux和Windows平台,并实现跨平台的函数调用。 ... [详细]
author-avatar
兰州老头_337
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有