当前位置: 首页 > news >正文

超前引用

所谓超前引用是指一个类型在定义之前就被用来定义变量和声明函数。     一般情况下,C/C++要求所有的类型必须在使用前被定义,但是在一些特殊情况下,这种要求无法满足, 例如,在类CMyView中保留了一个非模式对话框对象指针,该对象用于显示/修改一些信息。为了实现对话框 “应用”按钮,把对话框做的修改立刻更新到view界面上,为此,需要在对话框类中需要保存view类的指针,这样 定义关系就变成如下的代码:
    #ifndef __MYVIEW_H__     #define __MYVIEW_H__     //这是view类的头函数     #include "MyDialog.h"     class CMyView::public CView     {     protected:         CMyDialog * pDlg;         //这里是其他定义     };     #endif         #ifndef __MYDIALOG_H__     #define __MYDIALOG_H__     //这是对话框类的定义     #include "MyView.h"     class CMyDialog::public CDialog     {         protected:             CMyView * pView;             //其他定义     };     #endif         从编译器角度看,编译MyDialog.CPP时,系统首先定义宏__MYDIALOG_H__,然后包含MyView.h,MyView.h中 的#include "MyDialog.h"由于__MYDIALOG_H__已经定义,所以不再起作用。在CMyView类的声明中,         CMyDialog* pDlg ; 就会让编译器产生“CMyDialog"类型没有定义之类的错误,编译MyView.CPP文件出现的错误可以类似得到。         更一般的情况,类A和类B需要彼此互相引用,这样必然有一个类会先被定义,而另外一个类后被定义,这样在 先被定义的类引用后被定义的类的时候,就导致了所谓的超前引用。
    超前引用导致的错误有以下几种处理办法:     1) 使用类声明     在超前引用一个类之前,首先用一个特殊的语句说明该标识符是一个类名,即将被超前引用。其使用方法是:             a)  用class ClassB;声明即将超前引用的类名             b)  定义class ClassA             c)  定义class ClassB;             d)  编制两个类的实现代码。     上述方法适用于所有代码在同一个文件中,一般情况下,ClassA和ClassB分别有自己的头文件和cpp文件,这种 方法需要演变成:             a) 分别定义ClassA和ClassB,并在cpp文件中实现之             b) 在两个头文件的开头分别用class ClassB;和class ClassA;声明对方             c) 在两个cpp文件中分别包含另外一个类的头文件      NOTE:这种方法切记不可使用类名来定义变量和函数的变量参数,只可用来定义引用或者指针。           2) 使用全局变量      由于全局变量可以避免超前引用,不用赘述。我的习惯是,把类对象的extern语句加在该类头文件的最后,大家喜欢 怎样写那都没有什么大问题,关键是保证不要在头文件中胡乱包含。     3) 使用基类指针。     这种方法是在引用超前引用类的地方一律用基类指针。而一般情况下,两个互相引用的类并不涉及其基类,因此不会造成 超前引用。以开始的例子说:在CMyDialog类中用CView*代替CMyView*,在CMyView类中用CDialog*代替CMyDialog*,这样必然 不会造成超前引用。
    说明:本文中,为了叙述方便,把class AClass;语句成为类AClass的声明,把class AClass开始的对AClass的类成员变量、 成员函数原型等的说明称为类的定义,而把在CPP中的部分称为类的定义。如果大家对这三个词有不同的理解,请按照自己的本意 把这三个词换成相应的词来理解。

最新评论 [发表评论]查看所有评论 推荐给好友 打印
若类B要包含类A对象,则在类B定义之前必须对类A进行定义,否则只能包含类A的引用或指针,并且在类B定义之前必须声明类A,反之同理 ( jayden 发表于 2010-4-22 9:38:00)
<strong>诚招VC程序员写书</strong> 在当前的经济危机、工作难找的情况下,您是否想过兼职呢?多一份工作,多一份收入。
优厚的稿酬,诚招VC技术人员参与VC技术书籍出版。 通过该书籍,作者可以得到如下报酬: 1、丰厚的稿酬。 2、书籍著作的署名权。 3、对作者和书进行宣传,提高作者在技术圈子里的名气。 可异地兼职,如果您有这方面的兴趣和能力,请与我联系。
Email:jxsdhl@hotmail.com QQ:614723657 ( jxsdvc 发表于 2009-7-9 15:54:00)
同意!自身类的对象,是不可以作该类的成员的(不管是直接还是间接),但是指针和引用可以! ( tomyne 发表于 2002-12-11 14:33:00)
Thank sunshineormer@msn.com ( 林山 发表于 2002-11-22 9:41:00)
我说的初始化是先在内存中生成类的定义 ( sunshineormer@msn.com 发表于 2002-11-21 14:09:00)
#include <iostream> #include <string> using namespace std; class CA;
class CB { public: CB() {}; ~CB() {}; void Display () { string s = "This is Class B"; cout<<s<<endl; } CA* Aobject; };
class CA { public: CA() {}; ~CA() {}; CB Bobject; void Display () { cout<<"This is Class A"<<endl; }
};
int main() {
CA AObject;
return 0; } ( sunshineormer 发表于 2002-11-21 14:07:00)
/* 林山:   你不觉得你的定义是一个死循环吗?   在编译初始化的时候,对于类内部的类对象(成员函数)是先初始化的(注意,是对象,而不是对象指针), 你的程序中是AClass 变量Bobject 先调用bobject的初始化函数,然后B又调用其中A的初始化函数,以此类推。这样,编译器就无法得到B类的大小 ,自然编译也就失败了,对于一个未知大小的类,自然是 undefined class   用指针可以,   */ ( sunshineormer 发表于 2002-11-21 14:07:00)
我试了一下,还是有点问题.请大家指教.源代码如下 #include "stdafx.h" class BClass; class AClass;
class AClass { public: AClass() {}; ~AClass() {}; BClass Bobject; void Display () {printf ("This is Class A\n");}
};
class BClass { public: BClass() {}; ~BClass() {}; void Display () {printf ("\nThis is Class B\n");}; AClass Aobject; };
int main(int argc, char* argv[]) { printf("Hello World!\n"); BClass BObject; BObject.Aobject.Display(); return 0; } 编译提示说 "error C2079: 'Bobject' uses undefined class 'BClass'"
( 林山 发表于 2002-11-21 10:23:00)
敢问头文件前的宏定义和#include "XXX.h"是什么关系?MyView.h中的#include "MyDialog.h"由于_MYDIALOG_H__已经定义,所以不再起作用 这句话怎么理解呢.请指教,谢谢! ( 林山 发表于 2002-11-21 9:14:00)

转载于:https://www.cnblogs.com/lzhitian/archive/2012/01/25/2329311.html

相关文章:

  • Java中的volatile关键字-转载
  • jsp---EL存取器
  • 如何可以导入注册表文件时不提示?
  • 第八章异常和断言
  • VC++播放音频文件和音频数据的方法
  • ubuntu ftp服务器配置(转)
  • shell算数运算
  • 集线器、路由器、交换机、第三层交换技术
  • Slideshow ad
  • 13.6.1 新添加一个界面(Adding One Interface)
  • asp.net 机试题1
  • 第二节 1面向对像简介
  • basic4android 开发教程翻译(八)使用ListView
  • 虚拟机安装Linux怎么使桌面铺满虚拟机
  • xml.exist() 实例演示
  • [case10]使用RSQL实现端到端的动态查询
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • ES6核心特性
  • java2019面试题北京
  • linux安装openssl、swoole等扩展的具体步骤
  • Redis在Web项目中的应用与实践
  • Vue2.x学习三:事件处理生命周期钩子
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 跨域
  • 排序(1):冒泡排序
  • 判断客户端类型,Android,iOS,PC
  • 前端js -- this指向总结。
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • 译自由幺半群
  • 《天龙八部3D》Unity技术方案揭秘
  • 通过调用文摘列表API获取文摘
  • ​LeetCode解法汇总518. 零钱兑换 II
  • #微信小程序:微信小程序常见的配置传值
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (11)MATLAB PCA+SVM 人脸识别
  • (floyd+补集) poj 3275
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (python)数据结构---字典
  • (二)WCF的Binding模型
  • (二)正点原子I.MX6ULL u-boot移植
  • (附源码)计算机毕业设计SSM疫情社区管理系统
  • (三)Honghu Cloud云架构一定时调度平台
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转)LINQ之路
  • (转)shell中括号的特殊用法 linux if多条件判断
  • (状压dp)uva 10817 Headmaster's Headache
  • .NET Conf 2023 回顾 – 庆祝社区、创新和 .NET 8 的发布
  • .Net FrameWork总结
  • .NET MVC第五章、模型绑定获取表单数据
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .net 使用$.ajax实现从前台调用后台方法(包含静态方法和非静态方法调用)
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况