c++ - 重构导致链接器出现重复问题

标签 c++

我希望将一些包装器代码作为仅包含 header 的库。我受到 boost 库的启发,只保留它们的标题,以便简化分发 .lib 和包括编译 .cpp 的需要。

在此示例中,“z.h”是包装器,a.cp​​p 已重构为将 B() 移动到它自己的源文件中。现在它不起作用。

z.h

class Z
{
    public:
    void Foo(); // edited to match my code
};

Z::Foo() { } 

a.cpp

#include "z.h"
void A() { 
      Z z;
      z.Foo();
}
//void B(Z z) {
//     z.Foo();
//}

b.cpp

#include "z.h"
void B(Z z) {           
      z.Foo();
}

*error LNK2005: "public: __cdecl void z::Foo()"已经在 b.obj 中定义*

我知道我可以通过将 z.h 分成用于声明的 z.h 和用于定义的 z.cpp 来解决这个问题。

  • 但是如果没有 .cpp 文件,Boost 库怎么能成功呢?
  • 是否所有内容都需要模板?
  • 什么代码可以放在 z.h 中?

最佳答案

暂时考虑一下这个标题:

// foo.hpp

void foo(int x)
{
    /* do something */
}

(标题守卫在这里不相关,它们按翻译单元工作。)我们现在有两个翻译单元:

// a.cpp

#include "foo.hpp"

和:

// b.cpp

#include "foo.hpp"

这最终所做的是定义 foo(int x) 两次,每个 TU 一次。根据单一定义规则 (ODR),不允许多重定义,虽然从技术上讲不需要诊断,但对编译器部分来说这样做很简单,因此你会得到错误。

幸运的是,有一个关键字 inline 改变了这种行为:

// foo.hpp

inline void foo(int x)
{
    /* do something */
}

这个关键字告诉链接器,如果它遇到多个定义,它可以自由选择一个定义并丢弃其余的。 (由您来确保这实际上没问题!)通过此更改,解决了之前的 ODR 违规问题并且程序可以编译。

现在,您已将 header 列为:

class Z      
{      
    public:      
    void Foo(){       
       //do stuff      
    }      
};     

这等同于:

class Z      
{      
    public:      
    void Foo();
};    

inline void Z::Foo(){       
       //do stuff      
    }

因为在类中定义的函数是隐式内联。 (这允许您将定义包含在多个翻译单元中而不会出错。)我怀疑您写的不是您帖子中的内容,而是类似这样的内容:

class Z      
{      
    public:      
    void Foo();
};    

void Z::Foo(){       
       //do stuff      
    }

inline 缺失。等价性丢失,创建了多个定义,并且您违反了 ODR。

解决方案是使用inline,或者通过定义类定义中的函数隐式使用它。就个人而言,我发现后者更清晰(因为你避免重复自己),并且更容易维护。 Boost 经常使用 inline 来避免对单一定义的需要。

关于c++ - 重构导致链接器出现重复问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11977601/

相关文章:

c++ - 此 C++ 代码是否会导致内存泄漏(强制转换数组 new)

c++ - 创建系统范围的资源 C++

c++ - 数组/指针加法

c++ - Floyd Steinberg 抖动灰色(pgm ascii)到黑白(pbm ascii)

c++ - cpp文件中的全局变量

python - 将 numpy.ndarray 转换为 opencv cv::Mat

c++ - 具有 DirectX 桌面框架的消费者-生产者线程

调用 delete[] 后仍可访问 C++ 指针数组

c++ - 是否有理由更喜欢一个变量的多个 unordered_map 而不是一个结构?

c++ - 如何在 OpenGL 中为屏幕上的给定像素找到对应的图元或顶点