c++学习笔记——单独编译

本文介绍了C++单独编译的好处,可使大型程序管理更便捷。以直角坐标转极坐标程序为例,阐述将程序分成头文件和两个源代码文件的方法。说明了头文件应包含的内容、包含方式,强调避免多重声明,还介绍了用#ifndef防止头文件重复包含。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单独编译

单独编译的好处:c++鼓励程序员将组件函数放在独立的文件中。单独编译这些文件,然后将他们链接成可执行的程序。如果只修改了一个文件,则可以只重新编译该文件,然后再它与其他文件的编译版本链接,可以使大型程序的管理更加便捷。

以下面这个程序为例:将直角坐标转换成极坐标的程序

// strctfun.cpp -- functions with a structure argument
#include <iostream>
#include <cmath>

// structure declarations
struct polar
{
    double distance;      // distance from origin
    double angle;         // direction from origin
};
struct rect
{
    double x;             // horizontal distance from origin
    double y;             // vertical distance from origin
};

// prototypes
polar rect_to_polar(rect xypos);
void show_polar(polar dapos);

int main()
{
    using namespace std;
    rect rplace;
    polar pplace;

    cout << "Enter the x and y values: ";
    while (cin >> rplace.x >> rplace.y)  // slick use of cin
    {
        pplace = rect_to_polar(rplace);
        show_polar(pplace);
        cout << "Next two numbers (q to quit): ";
    }
    cout << "Done.\n";
    return 0;
}

// convert rectangular to polar coordinates
polar rect_to_polar(rect xypos)
{
    using namespace std;
    polar answer;

    answer.distance =
        sqrt( xypos.x * xypos.x + xypos.y * xypos.y);
    answer.angle = atan2(xypos.y, xypos.x);
    return answer;      // returns a polar structure
}

// show polar coordinates, converting angle to degrees
void show_polar (polar dapos)
{
    using namespace std;
    const double Rad_to_deg = 57.29577951;

    cout << "distance = " << dapos.distance;
    cout << ", angle = " << dapos.angle * Rad_to_deg;
    cout << " degrees\n";
}

不能简单地以main()之后为界限,将原来的文件分成两个,因为main函数和其他两个函数都使用了同一个结构声明,因此这样分解的话,两个程序都必须包含这个声明。即使将这个结构声明都复制到两个文件中,需要修改结构时,必须同时修改这两个文件,很麻烦,有些大型程序都不止两个文件。

解决方法:使用#include来处理这种情况,将结构声明放在头文件中,然后每一个源代码文件中包含该头文件。这样想要修改结构时,只需在头文件中做一次改动即可。另外,还可以将函数原型放在头文件中。所以,可以将原来的程序分成三部分:

(1)头文件:包含结构声明和使用这些结构的函数的原型(注意不是函数定义)

(2)源代码文件:包含与结构有关的函数的代码

(3)源代码文件:包含调用与结构有关的函数的代码。

注意:不要将函数定义和变量声明放在头文件中,因为如果在头文件中包含一个函数定义,然后在其他两个文件(属于同一个程序)中包含该头文件,则同一个程序将包含同一个函数的两个定义,除函数是内联的,否则会出错。

头文件中应该包含的内容:

(1)函数原型 

(2)使用#define或const定义的符号常量

(3)结构声明(将结构声明放在头文件中是可以的,因为它不创建变量,而只是在源代码文件中声明结构变量时,告诉编译器如何创建给结构变量)

(3)类声明

(4)模板声明(模板声明不是被编译的代码,它们指示编译器如何生成与源代码中的函数调用相匹配的函数定义。)

(5)内联函数

头文件的文件名包含在<>中,编译器将会在存储标准头文件的主机系统中查找;如果文件包含在""中,则编译器将首先查找当前的工作目录或者源代码目录。如果没有在那里找到头文件,则将在标准位置查找,因此在包含自己的头文件时,应使用引号""而不是尖括号<>。

注意:只需将源代码文件加入到项目中,而不用加入头文件。这是因为#include指令管理头文件。另外,不要使用#include来包含源文件代码,这样做将导致多重声明。

在同一个文件中只能将同一个头文件包含一次。但是有时候会在不知情的情况下将头文件包含多次。例如,可能使用包含了另一个头文件的头文件。可以使用基于预处理器编译指令#ifndef(if not defined)的。

可以上面的代码分成一下三个部分:

(1)头文件

coordin.h

// coordin.h -- 结构模板和函数原型
// structure templates
#ifndef COORDIN_H_
//以前没有使用预处理编译指令#define定义名称COORDIN_N_时,才处理#ifndef和#endif之间的语句。
#define COORDIN_H_ 
//一般使用#define来定义符号常量,但只要将#define用于名称,就足以完成该名称的定义,就如此处。

struct polar
{
    double distance;    // distance from origin
    double angle;        // direction from origin
};
struct rect
{
    double x;        // horizontal distance from origin
    double y;        // vertical distance from origin
};

// 函数原型
polar rect_to_polar(rect xypos);
void show_polar(polar dapos); 

#endif

 对#ifndef的注解

#ifndef 是"if not defined"的简写,是预处理功能(宏定义、文件包含、条件编译)当中的条件编译,可以根据是否已经定义了一个变量来进行分支选择,其作用是:

1、防止头文件的重复包含和编译;

2、便于程序的调试和移植;

一般地,假如有一个C源文件(如sourcefile.cpp),它包含两个头文件(如headfile_1.h和headfile_2.h),而头文件headfile_2.h又包含了headfile_1.h,则最终的效果是该源文件包含了两次headfile_1.h。如果你在头文件里定义了结构体或者类类型,那么问题来了,编译时将会报重复定义的错误。加上条件编译"ifndef"则问题可解决:

它的格式就是如下:

#ifndef 标识符;//这里的标识符时任意的,但每个头文件的这个“标识”都应该是唯一的。标识的明明规则一般是头文件名全大写,前面加下划线,并把文件名中的"."也变成下划线,如这里的COORDIN_H_。

当第一次包含coordin.h文件时,由于没有定义COORDIN_H,条件为真,这样就会执行#infdef COORDIN_H和#endif之间的代码;当第二次包含coordin.h时,前面已经定义了COORDIN_H(也就是#define COORDIN_H这个语句的结果),条件为假,#infdef COORDIN_H和#endif之间的代码也就不会再次被包含,这样就避免了重定义。

小结:还是把头文件的内容都放在#ifndef和#endif中吧。不管你的头文件会不会被多个文件引用,你最好都加上这个。一般格式是这样的:

#ifndef <标识>
#define <标识>

…

…

#endif

注意:#ifndef起到的效果是防止一个源文件多次包含同一个头文件,而不是防止两个源文件包含同一个头文件。事实上,防止同一头文件被两个不同的源文件包含这种要求本身就是不合理的,头文件存在的价值就是被不同的源文件包含。

(2)file1.cpp:包含调用与结构有关的函数的代码

// file1.cpp -- example of a three-file program
#include <iostream>
#include "coordin.h" // structure templates, function prototypes
using namespace std;
int main()
{
    rect rplace;
    polar pplace;

    cout << "Enter the x and y values: ";
    while (cin >> rplace.x >> rplace.y)  // slick use of cin
    {
        pplace = rect_to_polar(rplace);
        show_polar(pplace);
        cout << "Next two numbers (q to quit): ";
    }
    cout << "Bye!\n";
// keep window open in MSVC++
/*
    cin.clear();
    while (cin.get() != '\n')
        continue;
    cin.get();
*/
    return 0; 
}

(2)file2.cpp(包含与结构有关的函数的代码,也就是函数定义)

// file2.cpp -- contains functions called in file1.cpp
#include <iostream>
#include <cmath>
#include "coordin.h" // structure templates, function prototypes

// convert rectangular to polar coordinates
polar rect_to_polar(rect xypos)
{
    using namespace std;
    polar answer;

    answer.distance =
        sqrt( xypos.x * xypos.x + xypos.y * xypos.y);
    answer.angle = atan2(xypos.y, xypos.x);
    return answer;      // returns a polar structure
}

// show polar coordinates, converting angle to degrees
void show_polar (polar dapos)
{
    using namespace std;
    const double Rad_to_deg = 57.29577951;

    cout << "distance = " << dapos.distance;
    cout << ", angle = " << dapos.angle * Rad_to_deg;
    cout << " degrees\n";
}

 多个库的链接

### 回答1: c语言中没有using namespace std;这个语句,这是C++语言中的语句。在C++中,using namespace std;的作用是引入命名空间std中的所有标识符,使得我们可以直接使用std命名空间中的函数和变量,而不需要在前面加上std::前缀。 ### 回答2: 在C++中,为了方便使用标准库中定义的函数、变量和类型,可以使用“命名空间”(namespace)的概念来避免名称冲突,也可以使代码更加清晰易读。 “using namespace std;”语句是C++中常用的命名空间引用方式,表示在当前代码文件中使用标准库中的所有内容(用std命名空间定义的)而不用显式地指定每一个成员的名称。这些内容包括输入/输出、字符串处理、数学函数库、容器和算法等等。不使用“using namespace std;”则需要在调用标准库中的函数之前写上“std::”前缀,例如std::cout<<"Hello world!";。 需要注意的是,在某些情况下,“using namespace std;”可能会导致命名冲突或产生不可预见的后果,因此不能盲目使用。为避免这种问题,可以根据需要选择性地引入特定的命名空间成员,或使用其他方法避免命名冲突。 ### 回答3: "C语言using namespace std;"这行代码不是C语言代码,而是C++语言代码。在C++中,using namespace std;意为使用命名空间std(表示standard,即标准命名空间),以便在程序中简化标准库的使用。 C++标准库提供了一大堆的类和函数,这些都是在命名空间std中定义的。在使用这些类和函数时,我们会写出std::cout,std::cin等形式,这样就显得比较繁琐。如果在代码的开头写上using namespace std;,程序就可以直接使用cout、cin等标准库的类和函数,避免了繁琐的std::前缀,让代码更加简洁易读。 但是,使用命名空间可能会存在命名冲突的问题。如果程序中同时使用了多个命名空间,可能会导致同名的函数或类产生冲突,无法正常编译运行。因此,在使用命名空间时,应该选择合适的命名空间,或者使用全限定名(全名,即包括命名空间)来避免这个问题。 最后,需要提醒的是,虽然using namespace std;可以帮助我们简化代码,但是不建议在头文件中使用这个语句。因为头文件被多个源文件包含时,使用using namespace std;语句会加入头文件中,导致编译错误或程序行为不可预期。因此,在头文件中最好不要使用using namespace std;,而是在源代码文件中使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值