实验于华中农业大学逸夫楼2017.3.10

在编写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类的构造函数中,采用初始化列表的方式初始化,否则也会出错。

文章来源:http://patmusing.blog.163.com/blog/static/135834960201038113714199/

关于C++中的前置声明(附程序运行图)的更多相关文章

  1. c++中的前置声明

    引用google c++编码规范: When you include a header file you introduce a dependency that will cause your cod ...

  2. c++中的namespace(附程序运行图)

    实验于华中农业大学逸夫楼2017.3.10 namespace中文意思是命名空间或者叫名字空间,传统的C++只有一个全局的namespace,但是由于现在的程序的规模越来越大,程序的分工越 来越细,全 ...

  3. C++中前置声明介绍

    前置声明是指对类.函数.模板或者结构体进行声明,仅仅是声明,不包含相关具体的定义.在很多场合我们可以用前置声明来代替#include语句. 类的前置声明只是告诉编译器这是一个类型,但无法告知类型的大小 ...

  4. C++中头文件相互包含与前置声明

    一.类嵌套的疑问 C++头文件重复包含实在是一个令人头痛的问题,前一段时间在做一个简单的数据结构演示程序的时候,不只一次的遇到这种问题.假设我们有两个类A和B,分别定义在各自的有文件A.h和B.h中, ...

  5. C++中前置声明的应用与陷阱

    前置声明的使用 有一定C++开发经验的朋友可能会遇到这样的场景:两个类A与B是强耦合关系,类A要引用B的对象,类B也要引用类A的对象.好的,不难,我的第一直觉让我写出这样的代码: // A.h #in ...

  6. 【原创】SystemVerilog中的typedef前置声明方式

    SystemVerilog中,为了是代码简洁.易记,允许用户根据个人需要使用typedef自定义数据类型名,常用的使用方法可参见"define和typedef区别".但是在Syst ...

  7. 编写Java程序,模拟五子棋博弈过程中的异常声明和异常抛出

    返回本章节 返回作业目录 需求说明: 模拟五子棋博弈过程中的异常声明和异常抛出,判断用户所下棋子的位置,是否超越了棋盘的边界. 棋盘的横坐标的范围为0-9,纵坐标范围为0-14,如果用户所放棋子的坐标 ...

  8. [转]从普通DLL中导出C++类 – dllexport和dllimport的使用方法(中英对照、附注解)

      这几天写几个小程序练手,在准备将一个类导出时,发现还真不知道如果不用MFC的扩展DLL,是怎么导出的.但我知道dllexport可以导出函数和变量,而且MFC扩展DLL就算是使用了MFC的功能,但 ...

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

    转载自http://www.cnblogs.com/staring-hxs/p/3244251.html 在编写C++程序的时候,偶尔需要用到前置声明(Forward declaration).下面的 ...

随机推荐

  1. jsp的九大内置对象和四个作用域

    request           请求对象            类型 javax.servlet.ServletRequest        作用域 Request response       ...

  2. 整型转字符串(convert int to char)优化实践

    0. 前言 其实基本都没什么机会做这么一个基础的优化,一般基础库里就有函数可以直接拿来用. 这里以snprintf为基准,给大家展示一下每一个优化带来的些许收益. 1. 优化过程 1.最初使用的是sn ...

  3. angular : direative : autoResize textarea auto resize

    今天为大家推出自己的auto resize 指令功能. 目的:解决textarea在给height的问题. 参考源码:http://monospaced.github.io/angular-elast ...

  4. RAC之常用方法-----新手入门

    年后换工作新入职,公司开发在使用RAC,之前居然一直没有了解过,独立开发的弊端,信息闭塞,而且自己也懒,这几天看了下RAC,确实很强大有木有. 什么是ARC 简单的说,RAC就是一个第三方库,他可以大 ...

  5. 从零开始部署小型企业级虚拟桌面 -- Vmware Horizon View 6 For Linux VDI -- 概念简介

    什么是桌面虚拟化? 桌面虚拟化有很多概念,此处谈论的,是指的一般企业使用的“服务器 + 虚拟机 + 云终端”的方式来实现的. 桌面虚拟化的原理是什么? 桌面虚拟化看上去高大上,实际上原理非常的简单.拿 ...

  6. 牛顿迭代法(Newton's Method)

    牛顿迭代法(Newton's Method) 简介 牛顿迭代法(简称牛顿法)由英国著名的数学家牛顿爵士最早提出.但是,这一方法在牛顿生前并未公开发表. 牛顿法的作用是使用迭代的方法来求解函数方程的根. ...

  7. Python 之 json 模块

    引言 对于做web开发的人来说,json文本必须要熟知与熟练使用的.大部分网站的API接口调用返回的数据,就是json格式的.如果看json对象所包含的内容,相信对熟悉Python的人开说,很快就能把 ...

  8. 每天一个Linux命令 7

    常用yum命令1)查询 yum list #查询所有可用软件包列表yum search 关键字 #搜索服务器上所有和关键字相关的包2)安装 yum -y install 包名选项: install 安 ...

  9. 3384/1750: [Usaco2004 Nov]Apple Catching 接苹果

    3384/1750: [Usaco2004 Nov]Apple Catching 接苹果 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 18  Solv ...

  10. poolingHttpclientConnectionmanager 使用

    在阅读 netflix zuul 的simpleHostRoutingFilter 中,发现了一些问题. 主要是关于poolingHttpclientConnectionmanager. 在寻找其中的 ...