2

如果您定义了一个用于做某事的类,那么使用它所需要做的就是包含一个包含其方法原型的头文件(.h 文件),但您不必包含类文件本身( .cpp 文件,其中包含类方法的实际实现),

这是否意味着 .cpp 文件必须具有与其头文件相同的名称,以便编译器匹配名称以定位 .cpp 文件?

或者

当编译器遇到函数(方法)调用时,它会转到头文件并查看它是否具有原型。然后它在其内置函数中搜索实现,如果没有找到它在当前目录中的所有 .cpp 文件中搜索?

还是两个假设都不正确?

4

3 回答 3

4

文件名在 C++ 中是无关紧要的。链接器将所有部分放在一起。在编译一些 C++ 代码时,您需要知道的只是事物名称的含义。这就是声明类定义的目的:它们引入名称,从而为编译器提供足够的信息来生成代码:

文件 1.cpp:

int f(int, bool);         // declaration

class Foo;                // class declaration

class Bar { int g(); };   // class definition (implies declaration)

int main()
{
    Foo * p;              // OK, Foo * is a complete type, since we know that
                          // "Foo" denotes a class

    // p->h();            // Error: We don't know what Foo actually is!

    Bar b;                // OK, we know how size and alignment for Bar

    int m = b.g();        // OK, we know what sort of function B::g() is

    int n = f(50, true);  // OK, we don't need to know what f does

    return m + n;
}

编译上述代码时,它将包含和的未解析符号。只要一个(并且只有一个)其他翻译单元包含这些符号的定义,链接器就可以解析它们并且程序可以成功链接:fB::g

文件 2.cpp:

int f(int n, bool b) { return b ? n * 2 : 50 - n; }

// include class definition here
int Bar::g() { return f(sizeof(Bar), sizeof(int) == sizeof(char)); }

基本规则是,你可以声明一个函数或一个类,或者定义一个类a 任意多次,但你只能定义一个函数和一个类成员函数一次。有一个例外:如果您将类成员函数的函数声明为inline,那么您实际上可以重复定义它,前提是所有定义都相同。

这条规则的推论是,您可以安全地将所有函数声明和类定义放入头文件并重复包含它,只要您在一个翻译单元中只提供一次实际定义。(并且该inline规则允许您在类定义中包含实际的成员函数定义——与声明一起定义的成员函数是隐式的inline。)

于 2013-01-20T11:40:12.853 回答
2

编译器只需要头文件。但是所有的 C++ 文件都需要编译,因此链接器可以生成最终的二进制文件。

于 2013-01-20T11:30:05.053 回答
1

为了生成程序,编译器需要两者。通常,从 C++ 到二进制文件的编译分两步进行,首先将每个 CPP 文件(也称为翻译单元)转换为目标文件(主要包含机器代码,但也包含地址表)。然后,目标文件相互连接(链接)(需要地址表),形成最终的可执行文件。通常,在头文件中,您会说“有一个带有这些参数和这个返回值的函数”。在目标文件中,对该函数的调用被记录为对该函数的引用。最后,在链接时,这个引用被解析为必须由其他目标文件提供的函数的实际地址。

于 2013-01-20T11:37:33.073 回答