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

代码一:

// ForwardDeclaration.h

#include

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

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

{

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

using namespace std;

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

class A

{

private:

B* b;

public:

A(B* b);

void someMethod();

};

class B

{

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

见:

c++ using 前置声明_C++ 类声明 类前置声明范例相关推荐

  1. c++ using 前置声明_C++ 类的前置声明

    今天在研究C++"接口与实现分离"的时候遇到了一个问题,看似很小,然后背后的东西确值得让人深思!感觉在学习的过程中有太多的为什么,而每一个为什么背后都隐藏着一些原理和目的,所以得多 ...

  2. 为什么基类的析构函数要声明成虚函数

    记得以后基类(父类) 的析构函数最好是声明为 虚函数 即:virtual 开发中遇到了一个比较傻逼的bug,也证明了理论与实际之间的差距. 在基类中没有声明其析构函数为虚函数,导致delete 释放操 ...

  3. c++学习笔记之基础---类内声明函数后在类外定义的一种方法

    在C++的"类"中经常遇到这样的函数, 返回值类型名 类名::函数成员名(参数表){ 函数体.} 双冒号的作用 ::域名解析符!返回值类型名 类名::函数成员名(参数表) { 函数 ...

  4. 类中成员函数声明后面的const的含义

    这个const一般是对类中成员函数属性的声明,但这个声明怪怪的,只能放在函数声明的尾部,大概是因为其它地方都已经被占用了.这个声明表示这个函数不会修改类中的任何数据成员.如果在编写const成员函数时 ...

  5. 为什么static成员的类型可以是类本身?又为什么非static成员被限定声明为其自身类对象的指针或引用?...

    看到<C++ Primer>中的一句话,才想起分析一下这个问题:"static 数据成员的类型可以是该成员所属的类类型.非 static 成员被限定声明为其自身类对象的指针或引用 ...

  6. 基类的析构函数不能被继承。_为什么要把C++类中的析构函数声明为虚函数?

    如题,当一个类为基类的时候,通常其析构函数被声明为虚函数,这是为啥? class BaseCls { public: BaseCls() { printf("BaseCls()n" ...

  7. C/Cpp / 类的前向声明、不完全类型和完全类型

    1.类的定义和声明也可以像函数一样分开. 栗子: class CSys; 上述声明被称为前向声明.对于CSys来说,其声明之后和定义之前,被称为不完全类型. 2.不完全类型的使用场景极其有限: (1) ...

  8. C语言存储类、作用域、声明周期、链接属性

    存储类.作用域.声明周期.链接属性 基本概念解析 存储类 作用域 生命周期 链接属性 总结 基本概念解析 存储类 1.存储类就是存储类型,也就是描述C语言变量在何种地方存储. 2.内存有多种管理方法, ...

  9. C++ 在派生类中使用using声明改变基类成员的可访问性

    通过在类的内部使用using声明语句 , 我们可以将该类的直接或间接基类中的任何可访问成员标记出来 (只限于非私有成员) .using声明语句中名字的访问权限由该using声明语句之前的访问说明符来决 ...

最新文章

  1. 2018年摩拜校招嵌入式工程师笔试卷
  2. define##的作用
  3. 牛腩新闻发布系统(2)使用存储过程查询表
  4. Boost:每个连接处理的测试程序
  5. VTK:可视化算法之ClipSphereCylinder
  6. Spring5的通信报文
  7. Python time 获取本地时间戳(包含毫秒)
  8. java中set怎么建int型_使用Array.setInt来填充Java中的数组
  9. 深度长文:地球真的进入“人类世”时期了吗?
  10. Android Glide数据更新及内存缓存、硬盘缓存清理
  11. WEB标准有什么好处?
  12. sysoper在oracle是什么意思,oracle用户 sysdba 与system,sysoper的区别
  13. 思维模型 SWOT分析
  14. 快速傅里叶变换(MATLAB实现)
  15. Eclipse快捷方式无法在桌面上打开
  16. 图片打印设置之适应边框打印
  17. 射极跟随器负载过重引起的失真问题(摘抄)
  18. 2021年京东最新炸年兽活动用脚本会怎样?JD炸年兽活动参与教程
  19. 蓝牙发射功率dBm换算,发射总能量公式
  20. 图像的压缩算法--尺寸压缩、格式压缩和品质压缩

热门文章

  1. 直播预告 | 小米人工智能部崔世起:小爱同学全双工技术实践
  2. 上有硬核理论下能操刀AI落地,这里走出来的人都有“开挂人生”
  3. 飞桨上线万能转换小工具,教你玩转TensorFlow、Caffe等模型迁移
  4. 不知道读什么好?这 16 篇最新论文,帮你轻松积攒知识点
  5. 经典论文复现 | 基于深度学习的图像超分辨率重建
  6. KMP字符串搜索算法
  7. 学习《送东阳马生序》
  8. stm32延时us寄存器_STM32延时函数的四种方法
  9. 有一种努力叫:靠 自 己!
  10. spring-aop相关概念