注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Mr.Right

不顾一切的去想,于是我们有了梦想。脚踏实地的去做,于是梦想成了现实。

 
 
 

日志

 
 
关于我

人生一年又一年,只要每年都有所积累,有所成长,都有那么一次自己认为满意的花开时刻就好。即使一时不顺,也要敞开胸怀。生命的荣枯并不是简单的重复,一时的得失不是成败的尺度。花开不是荣耀,而是一个美丽的结束,花谢也不是耻辱,而是一个低调的开始。

网易考拉推荐

C++ 类声明 类前置声明范例  

2013-02-17 21:19:21|  分类: 编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

在编写C++程序的时候,偶尔需要用到前置声明(Forward declaration)。下面的程序中,带注释的那行就是类B的前置说明。这是必须的,因为类A中用到了类B,而类B的声明出现在类A的后面。如果没有类B的前置说明,下面的程序将不同通过编译,编译器将会给出类似缺少类型说明符这样的出错提示。

代码一:

// ForwardDeclaration.h

#include <iostream>


using namespace std;




class B;             // 这是前置声明(Forward declaration)


class A


{


private:


         B* b;


public:


         A(B* b):b(b)


         {


         }




};




class B


{




};


// Main.cpp

#include "ForwardDeclaration.h"


int main(int argc, char** argv)


{


         B* b = new B();


         A* a = new A(b);




         delete a;


         delete b;




         return 0;


}

上面程序可以顺利编译和运行(几乎没有做什么,也没有输出)

 

是不是有了前置说明就万事大吉了呢?我们看看下面的代码(带阴影部分的代码是新增加的)

代码二:

// ForwardDeclaration.h

#include <iostream>

using namespace std;

 

class B;             // 这是前置声明(Forward declaration)

 

class A

{

private:

         B* b;

public:

         A(B* b):b(b)

         {

         }

 

         void someMethod()

         {

                   b->someMethod();                                                  // (1)

         }

};

 

class B

{

private:

public:

         void someMethod()

         {

                   cout << "something happened..." << endl;

         }

};

 

// Main.cpp

#include "ForwardDeclaration.h"

 

int main(int argc, char** argv)

{

         B* b = new B();

         A* a = new A(b);

 

         a->someMethod();

 

         delete a;

         delete b;

 

         return 0;

}

 

一编译,发现代码(1)处出错。出错提示往往包括(不同的编译器给出的提示会有所不同)

1.       使用了未定义的类型B

2.       “->somemethod”的左边必须指向类/结构/联合/泛型类型

 

原因:

1.       (1)处使用了类型B的定义,因为调用了类B中的一个成员函数。前置声明class B;仅仅声明了有一个B这样的类型,而并没有给出相关的定义,类B的相关定义,是在类A后面出现的,因此出现了编译错误;

2.       代码一之所以能够通过编译,是因为其中仅仅用到B这个类型,并没有用到类B的定义。

 

解决办法是什么?

将类的声明和类的实现(即类的定义)分离。如下所示:

// ForwardDeclaration.h   类的声明

#include <iostream>

using namespace std;

 

class B;             // 这是前置声明(Forward declaration)

 

class A

{

private:

         B* b;

public:

         A(B* b);

         void someMethod();

};

 

class B

{

private:

public:

         void someMethod();

};

 

// ForwardDeclaration.cpp        类的实现

#include "ForwardDeclaration.h"

 

A::A(B* b):b(b)

{

}

 

void A::someMethod()

{

         b->someMethod();

}

 

 

void B::someMethod()

{

         cout << "something happened..." << endl;

}

 

// Main.cpp

#include "ForwardDeclaration.h"

 

int main(int argc, char** argv)

{

         B* b = new B();

         A* a = new A(b);

 

         a->someMethod();

 

         delete a;

         delete b;

 

         return 0;

}

 

结论:

前置声明只能作为指针或引用,不能定义类的对象,自然也就不能调用对象中的方法了。

 

而且需要注意,如果将类A的成员变量B* b;改写成B& b;的话,必须要将bA类的构造函数中,采用初始化列表的方式初始化,否则也会出错。关于这点

见:


特殊数据类型成员变量的初始化

有些成员变量的数据类型比较特别,它们的初始化方式也和普通数据类型的成员变量有所不同。这些特殊的类型的成员变量包括:

a.       常量型成员变量

b.       引用型成员变量

c.        静态成员变量

d.       整型静态常量成员变量

e.       非整型静态常量成员变量

 

对于常量型成员变量和引用型成员变量的初始化,必须通过构造函数初始化列表的方式进行。在构造函数体内给常量型成员变量和引用型成员变量赋值的方式是行不通的。

 

静态成员变量的初始化也颇有点特别。

// Initialization of Special Data Member


#include <iostream>


using namespace std;


 


class BClass


{


public:


         BClass() : i(1), ci(2), ri(i)   // 对于常量型成员变量和引用型成员变量,必须通过

         {                                             // 参数化列表的方式进行初始化。在构造函数体内进

         }                                             // 行赋值的方式,是行不通的。

 


         void print_values()


         {


                   cout << "i =\t" << i << endl;


                   cout << "ci =\t" << ci << endl;


                   cout << "ri =\t" << ri << endl;


                   cout << "si =\t" << si << endl;


                   cout << "csi =\t" << csi << endl;


                  cout << "csi2 =\t" << csi2 << endl;


                   cout << "csd =\t" << csd << endl;


         }


private:


         int i;                                                          // 普通成员变量

         const int ci;                                             // 常量成员变量

         int &ri;                                                      // 引用成员变量

         static int si;                                             // 静态成员变量

         //static int si2 = 100;                             // error: 只有静态常量成员变量,才可以这样初始化

         static const int csi;                                // 静态常量成员变量

         static const int csi2 = 100;                   // 静态常量成员变量的初始化(Integral type)    (1)


         static const double csd;                      // 静态常量成员变量(non-Integral type)


         //static const double csd2 = 99.9;      // error: 只有静态常量整型数据成员才可以在类中初始化

};


 


// 静态成员变量的初始化(Integral type)


int BClass::si = 0;


// 静态常量成员变量的初始化(Integral type)


const int BClass::csi = 1;


// 静态常量成员变量的初始化(non-Integral type)


const double BClass::csd = 99.9;


 


// 在初始化(1)中的csi2时,根据Stanley B. Lippman的说法下面这行是必须的。

// 在G++, VC2005中,下面这行则可有可无,这个和编译器有关。

const int BClass::csi2;


 


int main(void)


{


         BClass b_class;


         b_class.print_values();


 


         return 0;


}


  评论这张
 
阅读(1011)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016