您的位置:首页 > 编程语言 > C语言/C++

关于C++中的前置声明

2015-10-27 20:08 295 查看
今天一朋友问及C++中的前置声明问题,下面是我给出的回答。


在编写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;的话,必须要将b在A类的构造函数中,采用初始化列表的方式初始化,否则也会出错。关于这点,详见:特殊数据类型成员变量的初始化

FROM: http://patmusing.blog.163.com/blog/static/135834960201038113714199/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: