所谓超前引用是指一个类型在定义之前就被用来定义变量和声明函数。 一般情况下,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) |