链接C++项目时出现多重定义错误

multiple definition error while linking C++ project

本文关键字:定义 错误 C++ 项目 链接      更新时间:2023-10-16

我在重新安排C++项目以避免文件名和命名空间冲突时遇到了这个问题。

所以,我在一个简单的项目上复制了这个问题,这是它的文件

文件客户端.hpp:-

#ifndef CLIENT_HPP
#define CLIENT_HPP

namespace work { namespace test {
    int get_age(){
        return 33;
    }
}
}
#endif

文件工作.hpp:-

#ifndef WORK_HPP
#define WORK_HPP
#include <iostream>
#include "client.hpp"
namespace work { namespace test {
    class NewWork{
        public:
            NewWork(std::string name);
            std::string getName();
            int getAge();
        private:
            std::string _name;
    };
}
}
#endif

文件工作.cpp:-

#include "work.hpp"
using namespace work::test;
NewWork::NewWork(std::string name) : _name(name) {}
std::string NewWork::getName() { return _name; }
int NewWork::getAge() { return get_age(); }

文件main_fun.cpp:-

#include "work.hpp"
using namespace work::test;
int main(int argc, char **argv){
    NewWork w = NewWork("hari");
    std::cout << "Name: " << w.getName()
        << " Age: " << w.getAge()
        << std::endl;
    return 0;
}

文件CMakeLists.txt:-

cmake_minimum_required(VERSION 2.6)
project(work)
set(PROJECT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set ( SRC_FILES 
     ${PROJECT_DIR}/work.cpp
     ${PROJECT_DIR}/main_fun.cpp
     )
 include_directories(${PROJECT_DIR})
 add_executable(${PROJECT_NAME} ${SRC_FILES})

所以在构建这个时,我得到了以下错误:-

Linking CXX executable work
CMakeFiles/work.dir/main_fun.cpp.o: In function `work::test::get_age()':
main_fun.cpp:(.text+0x0): multiple definition of `work::test::get_age()'
CMakeFiles/work.dir/work.cpp.o:work.cpp:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
make[2]: *** [work] Error 1
make[1]: *** [CMakeFiles/work.dir/all] Error 2
make: *** [all] Error 2

我发现的一件事是,如果我让函数工作::test::get_age()到static,那么它编译和链接就没有任何问题。我不明白为什么它能和static一起工作。

头文件的保护是正确的,所以不可能多次包含它,或者我在这里遗漏了什么?

谢谢你,

Haridas N.

您在标头中定义了get_age。这意味着它被复制到每个翻译单元中,由每个.cpp中的#include复制。

当您在名称空间范围中将其标记为static时,这将使每个副本都成为该翻译单元的"本地"副本,这样就不会发生冲突。

如果您将其标记为inline,您将向编译器和链接器承诺,每个翻译单元中的定义都是相同的(我们可以看到这一点),因此多个副本将神奇地汇总为一个。

不过,正确的方法是在头中声明,并在一个源文件中定义

当包含client.hpp文件时,get_age函数是定义的。如果您将头文件包含在多个源文件中,那么您将拥有该函数的多个定义。

您应该做的是在头文件中声明函数,然后在单个源文件中定义它。

所以在头文件中只做

namespace work {
namespace test {
    int get_age();
}
}

并在源文件中创建定义

int work::test::get_age() {
    ...
}

声明函数inline(正如您在标头中提供的实现…)