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

时间:2013-11-19 11:45:35

标签: c++ c++11

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

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

文件client.hpp: -

#ifndef CLIENT_HPP
#define CLIENT_HPP


namespace work { namespace test {

    int get_age(){
        return 33;
    }

}
}

#endif

文件work.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

文件work.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

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

头文件的保护是正确的,所以不能多次包含它,或者我在这里遗漏任何东西?

谢谢,

Haridas N。

3 个答案:

答案 0 :(得分:4)

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

在命名空间范围内标记static时,会使每个副本“本地”到该翻译单元,因此不会发生冲突。

如果你将它标记为inline,你会向编译器和链接器承诺每个翻译单元中的定义是相同的(我们可以看到它),因此多个副本将被神奇地卷入只有一个。

但是,正确的方法是在标题中声明,并在一个源文件中 define ,就像使用类的成员函数一样。

答案 1 :(得分:3)

当您加入client.hpp文件时,get_age功能已定义。如果您将头文件包含在多个源文件中,那么您将拥有此函数的多个定义。

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

所以在头文件中只做

namespace work {
namespace test {

    int get_age();
}
}

在源文件中创建定义

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

答案 2 :(得分:1)

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