具有安全防护的多重定义

时间:2014-01-04 15:31:39

标签: c++ templates c++11 g++

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

template.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

template.cpp

#include "template.h"

body.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_会阻止重复包含。但似乎没有。可能我想念那里的东西?

2 个答案:

答案 0 :(得分:2)

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

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

// .h file
extern S s1;

// source file
Header::S Header::s1(Header::Header2::s1);

答案 1 :(得分:1)

包含警卫只会停止在同一翻译单元中包含两次相同的标题(相同的.cpp文件,类型)。当然,标题意味着包含在多个文件中。在某些翻译单元中,某些内容可以并且不会出现过多次。其中一个是命名空间范围的变量定义。

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

extern S s1;

但是你需要在某处定义它,所以在 .cpp文件中,你需要:

S s1(Header2::s1);

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