命名空间和模块化编程2

时间:2021-05-01 22:24:55

使用头文件:

  在创建了头文件之后,只要把它的文件名用双引号括起来写在如下所示的指令里就可以导入它:#include "fishc.h"

  如果没有给出路径名,编译器将到当前子目录以及当前开发环境中的其他逻辑子目录里去寻找头文件。为了消除这种猜测,在导入自己的头文件时可以使用相对路径。如果头文件与主程序文件在同一个子目录里,则可以这么写:#include "./fishc.h",Windows下则为#include ".\\fishc.h"。

  如果头文件位于某个下级子目录里,那么以下级子自录的名字开头:#include "下级子自录的名字/fishc.h"
  最后,如果头文件位于某个与当前子目录平行的"兄弟"子目录里,则需要这么写:#include "../兄弟子目录名字/fishc.h"
  请务必注意,Windows通常使用反斜朽作为路径名里的分隔符。反斜杠在字符串里表示转义符,表示一个反斜杠则需要用双反斜杠表示。
请看演示:Example命名空间和模块化编程2

 

fishc.h:

//fishc.h
//Create by xiaojiayu
//20190308

//只声明了下函数 

void call_love_fishc(); 

 

main.cpp:

#include <iostream>
#include "fishc.h"

int main()
{
	call_love_fishc();
	
	return 0;
}

void call_love_fishc()
{
	int i, j;
	int n = 10;
	for(i = 1 - (n >> 1); i <= n; i++)
	{
		std::cout<< "I love FISHC.com";
		if( i >= 0)
		{
			for(j = 0; j < i; j++)
				std::cout << "  ";
			for(j = 1; j < 2*(n-i)+1; j++) 
				std::cout << " *";
			std::cout << std::endl;
		}
		else{
			for(j = i; j < 0; j++)
				std::cout << "  ";
			for(j = 1; j <= n+2*i+1; j++)
				std::cout<<" *";
			for(j = 1; j <= -1-2*i; j++)
				std::cout<<"  ";
			for(j = 1; j <= n+2*i+1; j++)
				std::cout<<" *";
			std::cout << std::endl;
		}
	}
}

  

创建实现文件
  回到Rational这个栗子,我们带大家来进一步实现模块化编程。
  rational.h头文件包含Rational类的声明,但不包含这个类的实现代码。这种分割可能刚开始接触的朋友觉得有点奇怪,但在实践中非常普漏。因为把接口(函数的原型)和实现(函数体的定义)分开是对代码进行模块化的基本原则之一。

  头文件的重要性不仅体现在它们可以告诉编译器某个类、结构或函数将有着怎样的行为,还体现在它们可以把这些消息告诉给程序员。
  作为苦逼程序猿一枚,你只需看到函数的声明就可以了解到你需要知道的一切:函数的名字,它的返回值类型和它的输入参数的类型和数量。知道了这些东西,你就可以使用那个函数了,而根本用不着关心它到底是如何工作的。

  编译器就不同了,它必须读取某个类或函数的实现代码。
  作为一个通用原则,应该把声明放在一个头文件里,把实现代码放在一个.cpp文件里。
  现在我们就演示下rational这个程序如何分开和拼凑成一个完整的程序。Linux下编译多个文件:g++ -o rational.cpp main.cpp,Windows下则用ide编译器新建一个project使用。命名空间和模块化编程2

C/C++预处理器
  刚才的示例程序还有一个小小的问题需要解决,就是rationcal.cpp和main.cpp文件都包含了rational.h头文件。
  这意味着rational.h类被声明了两次,这显然没有必要(如果它是一个结构,声明两次还将导致编译器报错呢~)。解决方案之一是把其中一个文件里的#includel掉即可。这固然很容易可以解决的问题,但却会给今后留下麻烦。。。。。。

  当然我们在这里提出是因为有更好的解决方案!利用C++预处理器(C与C++预处理器相同),我们可以让头文件只在这个类还没有被声明过的情况下才声明它。
 预处理器的条件指令:命名空间和模块化编程2

  以前的课程中,我们曾经建议大家注释很多段代码的话用预处理的方式,比起/* */要效果好:

#if 0
    //这里有代码
    //这里有好多代码
    //这里有好多好多代码
    //这里有好多好多好多代码
#endif

  

#ifndef LOVE_FISHC
#define LOVE_FISHC
#endif

  这看起来好像没什么用,但事实却并非如此。这段代码的含义是:如果LOVE_FISHC还没有定义则定义之,看出这有什么作用了吗?

#ifndef LOVE_FISHC
#define LOVE_FISHC
class Rational{ ... };
#endif

  如果LOVE FISHC还没有定义,这里将发生雨件事儿:定义一次LOVE_FISHC,然后对Rational类做出声明等操作。
  这样一来,即使包含着这段代码的文件在某个项自里被导入了100次,Rational类也只会被声明一次,因为在第一次之后LOVE_FISHC就有定义!
  作为一种固定模式,这里使用的常量名通常与相应的文件名保持一致,把句点替换为下划线。

rational.h:命名空间和模块化编程2

 

 

ration.cpp:命名空间和模块化编程2

 

main.cpp:命名空间和模块化编程2