代码之家  ›  专栏  ›  技术社区  ›  Flying Hat

写入仅标头的模板库时出现“多重定义”错误

  •  1
  • Flying Hat  · 技术社区  · 11 年前

    当我需要使用 my_template_library.h 在里面 main_class.h .

    主.cpp

    #include "main_class.h"
    
    int main()
    {
        MainClass m;
        return m.exec();
    }
    

    main_类.h

    #ifndef MAIN_CLASS_H
    #define MAIN_CLASS_H
    
    #include "my_template_library.h"
    
    class MainClass {
    public:
        MainClass();
        int exec();
    };
    
    #endif // MAIN_CLASS_H
    

    主类.cpp

    #include <iostream>
    
    #include "main_class.h"
    
    MainClass::MainClass(){}
    
    int MainClass::exec()
    {
        std::cout << "exec!" << std::endl;
        return 0;
    }
    

    我的模板库.h

    #ifndef MY_TEMPLATE_LIBRARY_H
    #define MY_TEMPLATE_LIBRARY_H
    
    #include <iostream>
    
    //#pragma message ("I'm being included past the include guards!")
    
    class MyTemplateLibrary
    {
    public:
        MyTemplateLibrary();
    
        void function();
    };
    
    MyTemplateLibrary::MyTemplateLibrary(){}
    
    void MyTemplateLibrary::function()
    {
        std::cout << "function called!" << std::endl;
    }
    
    #endif // MY_TEMPLATE_LIBRARY_H
    

    在我编写的模板头库中,我首先声明类中的所有内容,然后定义类之外的所有内容 .h .cpp 代码,但带有 .cpp文件 在末尾添加的文件 .h时 ,内部包括防护装置。只要我的模板库只包含一次,这就很好了,但当它开始包含的次数超过一次时,我遇到了一些非常令人困惑的问题。

    $ g++ -o test main.cpp main_class.h main_class.cpp my_template_library.h 
    /tmp/ccuFlEDZ.o: In function `MyTemplateLibrary::MyTemplateLibrary()':
    main_class.cpp:(.text+0x0): multiple definition of `MyTemplateLibrary::MyTemplateLibrary()'
    /tmp/ccZikorv.o:main.cpp:(.text+0x0): first defined here
    /tmp/ccuFlEDZ.o: In function `MyTemplateLibrary::MyTemplateLibrary()':
    main_class.cpp:(.text+0x0): multiple definition of `MyTemplateLibrary::MyTemplateLibrary()'
    /tmp/ccZikorv.o:main.cpp:(.text+0x0): first defined here
    /tmp/ccuFlEDZ.o: In function `MyTemplateLibrary::function()':
    main_class.cpp:(.text+0xa): multiple definition of `MyTemplateLibrary::function()'
    /tmp/ccZikorv.o:main.cpp:(.text+0xa): first defined here
    collect2: error: ld returned 1 exit status
    

    我对发生了什么感到困惑。我添加了 #pragma message 对mytemplatelibrary.h进行一些解释,您可以在代码中看到注释。当我取消注释并运行我得到的代码时

    $ g++ -o test main.cpp main_class.h main_class.cpp my_template_library.h 
    In file included from main_class.h:4:0,
                     from main.cpp:1:
    my_template_library.h:6:63: note: #pragma message: I'm being included past the include guards!
     #pragma message ("I'm being included past the include guards!")
                                                               ^
    In file included from main_class.h:4:0:
    my_template_library.h:6:63: note: #pragma message: I'm being included past the include guards!
     #pragma message ("I'm being included past the include guards!")
                                                               ^
    In file included from main_class.h:4:0,
                 from main_class.cpp:3:
    my_template_library.h:6:63: note: #pragma message: I'm being included past the include guards!
     #pragma message ("I'm being included past the include guards!")
                                                               ^
    my_template_library.h:6:63: note: #pragma message: I'm being included past the include guards!
     #pragma message ("I'm being included past the include guards!")
                                                               ^
    /tmp/ccmawdhP.o: In function `MyTemplateLibrary::MyTemplateLibrary()':
    main_class.cpp:(.text+0x0): multiple definition of `MyTemplateLibrary::MyTemplateLibrary()'
    /tmp/cc4XSnui.o:main.cpp:(.text+0x0): first defined here
    /tmp/ccmawdhP.o: In function `MyTemplateLibrary::MyTemplateLibrary()':
    main_class.cpp:(.text+0x0): multiple definition of `MyTemplateLibrary::MyTemplateLibrary()'
    /tmp/cc4XSnui.o:main.cpp:(.text+0x0): first defined here
    /tmp/ccmawdhP.o: In function `MyTemplateLibrary::function()':
    main_class.cpp:(.text+0xa): multiple definition of `MyTemplateLibrary::function()'
    /tmp/cc4XSnui.o:main.cpp:(.text+0xa): first defined here
    collect2: error: ld returned 1 exit status
    

    因此,通过以下方式包含头文件:

    1. main.cpp->main_类.h
    2. main_类.h
    3. main_class.cpp->main_类.h
    4. my_template_library.h(自己?)

    所以,我的问题是:

    1. 为什么包括警卫没有帮助?
    2. 如何防止这种情况发生?
    1 回复  |  直到 11 年前
        1
  •  6
  •   Drew Dormann    11 年前

    为什么包括警卫没有帮助?

    相同的 编译单元。

    您收到关于的链接器错误 不同的 声称拥有相同函数定义的编译单元。

    如何防止这种情况发生?

    您需要创建那些非模板成员函数 inline 以避免违反 One Definition Rule .

    一种方法是显式地内联声明它们。

    inline MyTemplateLibrary::MyTemplateLibrary(){}
    

    或者,类定义中定义的函数是隐式内联的。

    class MyTemplateLibrary
    {
    public:
        MyTemplateLibrary() {}
    
        void function()
        {
            std::cout << "function called!" << std::endl;
        }
    };