chapter11 separate Compilition and Namespaces(part1)

来源:互联网 发布:杯子知乎 编辑:程序博客网 时间:2024/05/01 08:34

本文参考资料: Absolute C++

11.1 separate compilation

将一个C++的程序组织成几部分(separate parts), 在编写程序的时候有的时候是很重要的。 这样, 我们就可以随时查看我们感兴趣的部分。 试想, 如果把上千行的代码放在一个文件夹下, 会是一件多么让人头疼的一件事情。这不仅不符合模块化的编程思想, 为日后的修改维护增加了成本。相反, 如果程序员本身在编程的时候能够使程序“be distributeed across a number of files”, 定义好什么是.hpp头文件(interface 文件), 什么是.cpp 的implementation file,什么是主程序文件, 那么在未来当我们想要改变的程序的某些部分的时候, 只需要重新编译改变后的文件, 其他的部分保持不变即可。 

例如, 当我们想改变.hpp 中某个接口函数的实现形式, 但是不改变接口函数的prototype(函数原型, 又被称为signiture), 那么我们只需要改变对应的实现文件中的函数实现(定义), 然后保存, 其他的部分文件维持不变即可。 

  一个完整的C++ 程序的编译过程如下:


C++ 为dividing a program into parts that are kept in separate parts 提供了很多的facilities。 一旦我们程序的不同parts 保存在separate parts, 我们就可以compiled separately, and then linked together when the program is run。

对于C++, 一个重要的概念就是类。我们可以将class definition 放在一个独立的文件中, 将使用该类的程序部分放在在另一个文件中。 这样我们就可以在之前的那个存放文件中添加其他的class definition, 这个文件可以存放很错的classes, 这样我们就有了一个class library ,  许多程序都可以使用同一类(many programs can use the same class)。 z只需对这个类库编译一次, 就可以将其在任何的工程中使用。 一如C++ 中常用的头文件iostream, cstdlib 等文件。 不仅如此, 我们还可以将我们的这个文件分成两个文件, 从而使得我们的代码更加的polished。具体的做法如下:

we can define a class in 2 files, one file specifies what the class does, the other specifies how the class is implemented。这样, 当你仅仅想要改变类的实现(the implementation file)的时候, 仅仅需要recompile the file that contains the class implementation, 其他所有的files, 包括the files that use the class, 均不需要改变, 甚至不需要重新编译。 上述的内容和封装(‘Encapsulation’)有关。

Encapsulation

Encapsulation的规则就是将‘the specification of how the class is used by the programer’ 和‘the details of how the class is impemented’分离开。 这就是information hiding.。 也就是说使用者只知道类是如何用的, 而不知道类的具体实现细节。 要想完成这样的separatIon, 必须坚持如下三条规则:

rule1: 类的所有的成员变量(member variable)都声明为类的私有变量。

rule2: 在类的所有的基本操作(basic operation) 要么是类的public member function, 要么是类的friend function,要么是一个普通函数, 要么是重载的元算子(an overloaded operator)。 并且将类的definition(包括成员函数的declaration), 所有非成员函数的declaration(又称为prototype),以及operator declaration 归为一组。 这一group, 附上相应的  comments, 均放置在同一个文件中, 称为Interface file。NOTE: 必须注释清楚, 因为一个使用这个类的程序员所能看到的只有这个接口文件。

rule3:使得implementation of the basicoperation  unavailable to the programer who uses the class。 这个implementation file 中有函数的definitions,重载运算符的definitions, 以及其他的一些definitions。 这个文件就是implementation file。

在编写C++程序的时候, 遵守这些规则的最好办法就是将类的interface 和 类的 implementation 放在两个不同的文件中。 一个是interface file, 一个是implementation file。

通常一个典型的class 具有私有的成员变量(和私有成员函数), 私有成员变量(和私有成员函数)的存在对于 将一个类的接口(interface)和这个类的implementation放在两个文件中这个做法提出了问题。 因为类的共有部分是接口文件(interface)的一部分, 类的私有部分是implementation file的一部分。 但是C++ 不允许我们将类的定义拆开放在两个文件中。 所以, 我们必须需要把私有变量(私有函数)放在接口文件(interface file).。 然而这是okay 的。 因为尽管一个使用这个类的程序员能够看到这个接口文件的内容(写这个类的软件商提供了这个interface file), 他知道了这个类的私有成员, 但是他却不能使用, 所以事实上, 信息对于程序员来说仍然是隐藏的(hidden)。所以, 这实际上并没有violate封装的条件。

举一个例子:

Header files and implementation files

定义一个名为DigitalTime的class, DigitalTime 的值为一天的时间, 例如9:30, 该类使用24小时计数制, 例如, 输入1:30P.M, 输出13:30。

我们将接口(the interface)放在dtime.h头文件(header file)中, 任何一个使用这个类的程序中必须包含如下的 include 的指导语句:

#include “dtime.h”
NOTE:当我们在写include 指导语句时, 一定要清楚头文件是否为编译器提供给你的predefined header file, 例如 <iostream>,  <math.h>等等, 如果不是编译器提供的, 而是你写的头文件, 使用双引号括起头文件的名字, 如上面的 “dtime.h” 头文件。 <>括起来的头文件和“”括起来的头文件之间的区别(distinction)在于: 告诉编译器where to look for the header file。 如果使用的是<>, 编译器搜索头文件的位置在系统默认的路径中或者括号内的路径中查找,如果是“ ”, 编译器(compiler) 在该源文件(即当前目录)所在的路径中查找, 如果未找到, 就在系统默认路径中查找。通常包含的是程序员自己编写的头文件。

值得记住的是, 一个接口文件(interface file)总是一个头文件(header file)。

另外, 除了头文件(即接口文件)以外, 我们还需要implementation file, 通常二者的名字相同, 只不过后缀不同(尽管二者名字可以不同, 但是最好是同样的名字)。

例如dtim.h和dtime.cpp

首先在code::blocks 建立工程MyFourth, 然后创建如下工程文件。

 

//interface file for the DigitalTime class
//This is the header file dtime.h//values of this type are times of the day. the values are input and output in24 hours notation//as in 9:30 for 9:30AM and 14:45 for 2:45PM
#ifndef DTIME_H#define DTIME_H#include <iostream>using namespace std;class DigitalTime{   public:   DigitalTime(int theHour,int theMinute);   DigitalTime();//initialize the time value to 0:00,which is midnight   int getHour() const;   int getMinute() const;   void advance(int minutesAdded);//changes the minutes to minutes Added minutes later   void advance(int hoursAdded, int minutesAdded);   //changes the time to hoursAdded hours and  minutesAdded minutes   friend bool operator ==(const DigitalTime& time1,const DigitalTime& time2);   friend istream& operator >>(istream& ins,DigitalTime& theObject);   friend ostream& operator <<(ostream& outs,const DigitalTime& theObject);   //输入当然不需要theObject为常物件,   //当然在读取时,为了避免更改,声明物件为const   private:   int hour;   int minute;   static void readHour(int& theHour);   static void readMinute(int& theMinute);   static int digitToInt(char c);};#endif

implementation file dtime.cpp文件 如下:
//This is the implementation file dtime.cpp of the class DigitalTime
//this is the implementation file dtime.cpp of class DigitalTime//The interface file for the class DigitalTime is in the header file dtime.h#include <iostream>#include <cctype>#include <cstdlib>using namespace std;#include "dtime.h"//uses iostream and cstdlibDigitalTime::DigitalTime(int theHour,int theMinute){   if(theHour < 0 || theHour > 24 || theMinute < 0 || theMinute > 59 ){      cout << "Illegal argument to DigitalTime constructor.";      exit(1);   }   else{      hour = theHour;      minute = theMinute;   }   if (theHour == 24){      hour = 0;//standardize midnight as 0:00   }}DigitalTime::DigitalTime(){hour = 0;minute = 0;}int DigitalTime::getHour() const{   return hour;}int DigitalTime::getMinute() const{   return minute;}void DigitalTime::advance(int minutesAdded){   int grossMinutes = minute + minutesAdded;   minute = grossMinutes%60;   int hourAdjustment = grossMinutes/60;   hour = (hour + hourAdjustment)%24;}void DigitalTime::advance(int hoursAdded,int minutesAdded){   hour = (hour + hoursAdded)%24;   advance(minutesAdded);}bool operator == (const DigitalTime& time1, const DigitalTime& time2){   return (time1.hour == time2.hour && time1.minute == time2.minute);}//uses iostreamostream& operator <<(ostream& outs,const DigitalTime& theObject){   outs << theObject.hour << ':';   if(theObject.minute<10)   outs << '0';   outs << theObject.minute;   return outs;}// uses iostreamistream& operator >>(istream& ins ,  DigitalTime& theObject){   DigitalTime::readHour(theObject.hour);   DigitalTime::readMinute(theObject.minute);   return ins;}int DigitalTime::digitToInt(char c){   return (int(c)-int('0'));}//uses iostream ,cctype,and cstlibvoid DigitalTime::readMinute(int& theMinute){   char c1,c2;   cin >> c1 >> c2;   if (!(isdigit(c1)&&isdigit(c2))){      cout << "Error:illeagal input to readMinute\n";      exit(1);   }   theMinute =digitToInt(c1)*10 + digitToInt(c2);   if (theMinute <0 || theMinute > 59){      cout << "Error:illegal input to readMinute\n";      exit(1);   }}// uses iostream,cctype,and cstlib:void DigitalTime:: readHour(int& theHour){   char c1,c2;   cin >> c1 >> c2;   if(!(isdigit(c1) && (isdigit(c2)|| c2 ==':'))){      cout << "Error:illegal input to ReadHour\n";      exit(1);      }    if(isdigit(c1) && c2 ==':'){       theHour = DigitalTime::digitToInt(c1);    }    else{       theHour = DigitalTime::digitToInt(c1)*10+DigitalTime::digitToInt(c2);       cin >> c2;       if(c2 !=':'){          cout << "Error: illegal input to readHour\n";          exit(1);       }       }    if(theHour == 24)    theHour = 0;    if(theHour<0 || theHour >23){       cout << "Error: illegal input to readHour\n";       exit(1);    }}

Application file using DigitalTime class, 文件名字
 
//Application file
//this is the appliction file which demonstrates use of DigitalTime#include <iostream>using namespace std;#include "dtime.h"int main(){   DigitalTime clock, oldClock;   cout << "you may write midnight as either 0:00 or 24:00\n"        << "but I will write it as 0:00\n"        << "Enter the time in 24-hour notation: ";   cin >> clock ;   oldClock = clock;   clock.advance(15);   if(clock == oldClock)      cout << "something is wrong";   cout << "you entered " << oldClock << endl;   cout << "15 minutes later the time will be "        << clock << endl;   clock.advance(2,45);   cout << "2 hours and 15 minutes later \n"        << "the time will be "        << clock << endl;   return 0;}

 

运行结果如下:





0 0
原创粉丝点击