是否可以实现仅表头的非模板类

Is it possible to implement header-only non-template class?

本文关键字:表头 实现 是否      更新时间:2023-10-16

就我的理解标准而言,在不违反One Definition Rule的情况下,在头中实现非模板和非内联的东西的唯一方法是实现匿名命名空间。

但我不确定在这样的类方法实现中静态变量会发生什么:

// MyHeader.h
// ... pragma once, defines, etc. ...
// (anonymous namespace removed due to suggestions below)
// namespace
// {
    class A // a simplified single-threaded kind of Singleton
    { 
        // ... some private not static data ...
    public:
        static A& instance() 
        {
            static A instance;   // is it guaranteed to be module-global?
            return instance;
        }
        void doNothing();
    }
    // inline added as suggested in answers below
    // actually, I disabled inline in compile settings,
    // checked that inlining was not happened using disassembler, 
    // but `inline` keyword is needed and it matters. Any suggestions, why?
    inline void A::doNothing()
    {
        // it's a very long method, so long that I don't want to 
        // implement it as inline within class body.
        // but not so long to consider refactoring it to smaller functions :)
    }        
//}
// File executable_part1.cpp
// ... includes, etc. ....
A::instance().doNothing();
// File executable_part2.cpp
// ... includes, etc. ....
A::instance().doNothing();

主要问题是:

  • 是否保证instance是模块全局的
  • 这种可移植代码或行为是由编译器实现定义的吗

我已经在Windows上的MSVS 2012上试用了此代码。我已经将这个头包含在3个模块中的每个模块的2.cpp文件中:一个可执行文件和两个由可执行文件加载的dll。总共6次。

没有命名空间:constructor被调用了3次,每个"操作系统级别"模块调用一次。使用namespace:cconstuctor被调用了6次,每个cpp文件调用一次。

更新:如下所述,C++’03标准的第7.1.2章解决了我的问题。内联在这里很重要。

您不应该使用未命名的命名空间,因为每个翻译单元都有自己的结构A。

只做

class A
{ 
    // ... some private not static data ...
public:
    static A& instance() 
    {
        static A instance;
        return instance;
    }
    void doNothing();
};
inline void A::doNothing()
{
    // it's a very long method, so long that I don't want to 
    // implement it as inline within class body.
    // but not so long to consider refactoring it to smaller functions :)
}
  • exe/dll之间不共享singleton是正常的
  • 有了未命名的命名空间,每个TU都有singleton,而没有它,整个exe(和分别为整个Dll)都共享singleton

对于您的配置:1个exe和2个cpp,2个Dll和两个cpp:你的实验是正确的:6个有未命名的命名空间,3个没有。

我真的不太理解这个问题(也许我错过了什么),所以保留你需要的。

据我所知,静态方法和数据属于类本身,而不属于类的实例。因此,静态数据只存在一次,如果从不同的对象访问这些数据,则它们独立地是相同的。静态方法类似于普通的外部函数,它们没有可用的this指针。属于类的命名空间,因此每个类都可以实现具有相同名称的静态函数,并且不会因为它们的名称不相等而发生名称冲突,因为完全限定名称是:"classOfApparttence::nameOfFunction",并且每个类的完全限定名称不同。本质上,如果您没有为类实现任何对象,那么该类就只是一个命名空间。