多重定义,安全防护

multiple definition with safe guard

本文关键字:安全防护 定义      更新时间:2023-10-16

header.h

#ifndef HEADER_H_
#define HEADER_H_
#include "cstdint"
namespace Header {
    namespace Header2 {
        enum { s1, s2, s3 };
    }
    struct S {
        uint32_t m_index;
        S(uint32_t index) : m_index(index) {}
    };
    S s1(Header2::s1);
}
#endif

模板.h

#ifndef CLASS_H_
#define CLASS_H_
#include "header.h"
#include "iostream"
template <class T>
class Class {
public:
    Class() {};
    void doSomething();
};
template <class T>
void Class<T>::doSomething() {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}
#endif

模板.cpp

#include "template.h"

正文.cpp

#include <iostream>
#include "header.h"
#include "template.h"
class A {
};
int main() {
    std::cout << Header::s1.m_index << std::endl;
    Class<A> c;
    c.doSomething();
    return 0;
}

$ g++ -Wall body.cpp template.cpp -o body -O3 -std=c++0x

/tmp/ccUYtE0g.o:(.bss+0x0): multiple definition of `Header::s1'
/tmp/cca2YIRL.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status

我认为安全防护#ifndef CLASS_H_可以防止重复包含。但似乎不是。 可能我在那里错过了什么?

包含防护可防止由于标头两次包含在同一个源文件中而导致的编译器错误。它们不能防止由两个定义同一对象的源文件引起的链接器错误(通常通过包含包含所述定义的标头)。

为了避免后一种错误,请不要在头文件中定义对象。在标头中声明它,在一个源中定义它。喜欢这个:

// .h file
extern S s1;
// source file
Header::S Header::s1(Header::Header2::s1);

包含守卫仅阻止在同一翻译单元(相同的.cpp文件)中包含两次相同的标头。当然,标头应该包含在多个文件中。有些内容可以在所有翻译单元中出现,也不能多次出现。其中之一是命名空间范围的变量定义。

要使s1的定义仅是一个声明(可以出现在多个翻译单元中),您需要将其设为 extern:

extern S s1;

但是你需要在某处有一个定义,所以在单个.cpp文件中,你需要有:

S s1(Header2::s1);

确保它们位于适当的命名空间中。