如果我试图在另一个文件中定义一个函数,链接器说它已经被定义(运行 测试)

Linker says a function is already defined if I try to define it in another file (running tests)

我在测试项目中有以下文件:

Test.cpp:

#include "pch.h"
#include "CppUnitTest.h"
#include <iostream>
#include "PrintOne.cpp"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace PointandVectorCreationTest
{
    TEST_CLASS(PointandVectorCreationTest)
    {
    public:
        
        TEST_METHOD(TestMethod1)
        {
            std::string expected = "1\n";

            std::stringstream buffer;
            std::streambuf* sbuf = std::cout.rdbuf(); // Save cout's buffer
            std::cout.rdbuf(buffer.rdbuf()); // Redirect cout to the stringstream buffer

            int result = printOne();

            // When finished, redirect cout to the original buffer 
            std::cout.rdbuf(sbuf);
            std::cout << "std original buffer: \n";
            std::cout << buffer.get();

            // Test
            Assert::AreEqual(expected, buffer.str());
        }
    };
}

PrintOne.cpp:

#include <iostream>

int printOne() {
    std::cout << 1 << std::endl;
    return 0;
}

当我在 Visual Studio 中尝试 运行 此测试时,链接器抛出以下错误:

Error LNK2005 "int __cdecl printOne(void)" (?printOne@@YAHXZ) already defined in PrintOne.obj

链接 Test.obj 时抛出此错误。

我没有在 Test.cpp 中的任何地方定义 printOne。事实上,如果我只是将函数的定义复制到 Test.cpp 并像这样删除 PrintOne.cpp 文件:

Test.cpp:

#include "pch.h"
#include "CppUnitTest.h"
#include <iostream>

int printOne() {
    std::cout << 1 << std::endl;
    return 0;
}

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace PointandVectorCreationTest
{
    TEST_CLASS(PointandVectorCreationTest)
    {
    public:
        
        TEST_METHOD(TestMethod1)
        {
            std::string expected = "1\n";

            std::stringstream buffer;
            std::streambuf* sbuf = std::cout.rdbuf(); // Save cout's buffer
            std::cout.rdbuf(buffer.rdbuf()); // Redirect cout to the stringstream buffer

            int result = printOne();

            // When finished, redirect cout to the original buffer 
            std::cout.rdbuf(sbuf);
            std::cout << "std original buffer: \n";
            std::cout << buffer.get();

            // Test
            Assert::AreEqual(expected, buffer.str());
        }
    };
}

测试运行很好。我宁愿避免在测试它们的同一个文件中编写我使用的所有函数,所以对我来说这不应该是一个解决方案。

为什么链接器会抛出这个异常?我该如何解决这个问题,以便将我的函数定义与测试文件分开?

I'm not defining printOne anywhere in Test.cpp.

其实你是,当你把PrintOne.cpp的源代码#include变成Test.cpp的时候。如果你然后编译 link Test.cppPrintOne.cpp 在一起,linker 确实看到 printOne() 的 2 个定义,每个 .obj 一个文件。

对于您尝试执行的操作,您需要添加一个 .h 文件,该文件仅 声明 printOne(),然后您可以 #include 那个文件到两个 .cpp 文件中,其中只有一个 定义 printOne(),例如:

Test.cpp:

#include "pch.h"
#include "CppUnitTest.h"
#include <iostream>
#include "PrintOne.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace PointandVectorCreationTest
{
    TEST_CLASS(PointandVectorCreationTest)
    {
    public:
        
        TEST_METHOD(TestMethod1)
        {
            std::string expected = "1\n";

            std::stringstream buffer;
            std::streambuf* sbuf = std::cout.rdbuf(); // Save cout's buffer
            std::cout.rdbuf(buffer.rdbuf()); // Redirect cout to the stringstream buffer

            int result = printOne();

            // When finished, redirect cout to the original buffer 
            std::cout.rdbuf(sbuf);
            std::cout << "std original buffer: \n";
            std::cout << buffer.get();

            // Test
            Assert::AreEqual(expected, buffer.str());
        }
    };
}

PrintOne.h

#pragma once
int printOne();

PrintOne.cpp:

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

int printOne() {
    std::cout << 1 << std::endl;
    return 0;
}

当你的 Test.cpp 文件中有像 #include "PrintOne.cpp" 这样的行时,PrintOne.cpp 的全部内容(包括 printOne() 函数的定义)将是包含在 Test.cpp 的源代码中;因此,Test.obj 文件将包含 printOne() 函数的定义。

如果你的项目中还包含 PrintOne.cpp 文件——从链接器引用 PrintOne.obj 模块这一事实看来——那么也会有 也是该目标文件中 printOne() 函数的定义。

因此,您有多个(虽然相同)函数定义,如链接器所指示的那样。

为避免这种情况,请将包含的 PrintOne.cpp source 文件替换为提供 declaration (prototype/signature) for the printOne function (源文件的内容将被添加,无论如何,如果它是项目的一部分。)

一般来说,#include ... 源 (cpp) 文件是不可取的(尽管在某些 情况下它可能有用)。值得一读: