如何从另一个 .cpp 文件中的一个 .cpp 文件调用函数?

新手上路,请多包涵

我尝试查找此内容并使用头文件等得到混合结果。

基本上,我有多个 .cpp 文件,其中包含我为使用二叉树、 BST 、链表等而制作的所有函数。

我不想复制和粘贴我需要的函数,我只想能够做一个:

 #include <myBSTFunctions.h>

并且能够调用和使用我自己的函数。

有哪些步骤来实现这一点?用我使用的所有函数原型制作一个头文件?

我应该将所有实际功能的 .cpp 和头文件放在哪里?

有没有办法直接调用函数文件的目录?

即,我更想将它与主要源 .cpp 文件放在同一个文件夹中,以便与我的一些同事共享。

我怎样才能做到这一点?

在 Windows 和 MinGW 编译器上。

原文由 Emrit 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
1 个回答

这篇文章是对现有答案的补充答案,这些答案没有解决一个非常常见的问题(尤其是在初学者中):包括在单独的源文件中实现的模板的头文件。


基本上,我有多个 .cpp 文件,其中包含我为使用二叉树、BST、链表等而制作的所有函数。

自从:

  • 您已经用 c++ 标记了您的问题,并且
  • C++ 有模板,并且
  • 你有类似容器的数据结构(BST、链表等),我假设它们使用模板

我想指出其他答案中未提及的一个常见问题。考虑以下两个文件:

文件 class.hpp

 #pragma once // Non-standard but supported by almost (if not) all compilers

// Some class
template<class T> class Class {
    T data;
public:
    Class();
};

// Some function
template<class T> T square(const T& x);

文件 class.cpp

 #include "class.hpp"
#include <iostream>

template<class T> Class<T>::Class()
{
    std::cout << "Class()" << '\n';
}

template<class T> T square(const T& x)
{
    return x*x;
}

尝试实例化一个 Class 对象,或调用 square()

 #include "class.hpp"
#include <iostream>

int main()
{
    Class<int> clss; // should output Class()
    std::cout << square<int>(3); // should print 9
}

编译:

 g++ class.cpp main.cpp -o cpptest.exe

 ./gcc/bin/ld.exe: main.cpp(.text+0x15): undefined reference to 'Class<int>::Class()'
./gcc/bin/ld.exe: main.cpp(.text+0x28): undefined reference to 'int square<int>(int const&)'


问题

1. 模板

想象一下你有这个功能:

 template<class T> T add(const T& x, const T& y)
{
    return x + y;
}

你这样称呼它:

 int res = add<int>(2, 3);

当编译器创建函数实现的副本时(即编译器看到对 add() 的调用时):

 int add(const int& x, const int& y)
{
    return x + y;
}

然后你的电话将变成:

 int res = add(2, 3);

这显然意味着模板函数实现必须在找到调用时对编译器可见,因此编译器将能够对其进行复制。为了让编译器找到/看到它,它必须在同一个 翻译单元 中。

这就是模板魔法在幕后工作的方式。有关更多信息,请参阅 此答案

2. 编译器和链接器

完成编译步骤:

  1. 将所有 #include 指令替换为包含的文件内容。
  2. 分别编译每个 .cpp 文件(也称为“翻译单元”)。结果将是每个单元的目标文件。请注意,某些代码(如 main.cpp 中的代码)是指另一个代码( class.cpp )。这将在下一步中解决。
  3. 将翻译单元完全链接到一个可执行文件中。 (有关更多详细信息,请参阅 JMAA答案)。

应用上面的步骤 1,我们将有两个翻译单元( .cpp 文件):

文件 class.cpp

 template<class T> class Class {
    T data;
public:
    Class();
};

template<class T> T square(const T& x);

/* <iostream> code ... */

template<class T> Class<T>::Class()
{
    std::cout << "Class()" << '\n';
}

template<class T> T square(const T& x)
{
    return x*x;
}

文件 main.cpp

 template<class T> class Class {
    T data;
public:
    Class();
};

template<class T> T square(const T& x);

/* <iostream> code ... */

int main()
{
    Class<int> clss;
    std::cout << square<int>(3);
}

应用上面的步骤 2,我们将只有地址(这不是真实目标代码的样子,它只是一个简化):

文件 class.cpp

 /* Nothing to generate for 'Class' definition. Remember, templates are just models (hence the word "template"), not concrete classes/functions. */

/* Nothing to generate for square()'s definition: It's a template, not concrete. */

iostream_object_code

/* Nothing to generate for 'Class' implementation. It's a template, not concrete. */

/* Nothing to generate for square()'s implementation: It's a template, not concrete. */

文件 main.cpp

 /* Class is not concrete: nothing is generated. */

/* square() is not concrete: nothing is generated. */

iostream_object_code

int main()
{
    class_int_obj_placeholder clss;
    __operator_xx(cout_obj_ref, fn100017(3));
}

应用上面的步骤 3,您将得到 undefined reference 错误:链接器不知道任何翻译单元中的任何 fn100017() 。因为 square() 是一个模板(或模型),编译器没有生成任何具体的实现。这同样适用于 Class

解决方案

  1. 显而易见的解决方法是将定义和实现放在同一个头文件中。这样,当包含在 main.cpp 中时,编译器都可以看到它们,因为它们在同一个翻译单元中。
  2. 或者,如果您想将定义和实现分开,请将您的实现放在头文件中,然后将其包含在定义头的末尾:

文件 class.hpp

 #pragma once

template<class T> class Class {
    T data;
public:
    Class();
};

template<class T> T square(const T& x);

#include "class_impl.hpp"

文件 class_impl.hpp

 #include <iostream>

template<class T> Class<T>::Class()
{
    std::cout << "Class()" << '\n';
}

template<class T> T square(const T& x)
{
    return x*x;
}

使用相同的命令编译和运行 main.cpp

 Class()
9

原文由 Zakk 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏