选择替代实现和前向声明

Choosing alternate implementations and forward declarations

我有一个库,其中有一个特定的 class 供下游客户端代码使用。这个 class 派生自一组基础 classes。例如,

A.h :-
namespace my_lib {
  class A : public BaseClass1 {
  };
}

现在,我想提供 class A 的另一种实现,它派生自另一组基 classes 并允许客户端选择编译哪一个 / link反对。因此,我想要某种方式在同一个 shared/static 库中发布这两个实现。

例如,

NewA.h :-
namespace my_lib {
  class newA : public BaseClass2 {
  };
}

我尝试使用 typedef,但这会导致前向声明出现问题。例如,

ClientA.h :-
namespace my_lib {
  #ifdef LEGACY_A
    typedef A ClientA;
  #else
    typedef NewA ClientA;
  #endif
}

因此,客户端只会使用 class 名称 my_lib::ClientA。但是,如果客户端有前向声明,这会导致下游出现问题。

例如,

clientclass.h :-
namespace my_lib {
  class ClientA;
  class clientClass {
    clientClass(ClientA* a);
  };
}

这给出了一个错误:-

clientclass.h: error: definition of type 'ClientA' conflicts with typedef of the same name
class ClientA;
      ^
ClientA.h: note: 'ClientA' declared here
typedef my_lib::newA ClientA;

另一方面,如果我使用命名空间和 using 指令,我又会遇到麻烦:-

A.h:-
namespace my_lib_legacy {
  class A : public BaseClass1 {
  };
}
newA.h :-
namespace my_lib_new {
  class A : public BaseClass2 {
  };
}
ClientA.h :-
namespace my_lib {
  #ifdef LEGACY_A
    using my_lib_legacy::A;
  #else
    using my_lib_new::A;
  #endif
}
clientclass.h :-
namespace my_lib {
  class A;
  class clientClass {
    clientClass(A* a);
  };
}

但是,这会引发歧义错误,如下所示:-

clientclass.h: error: reference to 'A' is ambiguous
  explicit clientClass(A* a)
                       ^
clientclass.h: note: candidate found by name lookup is 'my_lib::A'
class A;
      ^
ClientA.h: note: candidate found by name lookup is 'my_lib::A'
using my_lib_legacy::A;

如果我理解你的问题,你可以使用

ClientA.h :-
#include "A.h"
#include "NewA.h"
namespace my_lib {
  #ifdef LEGACY_A
    typedef A ClientA;
  #else
    typedef NewA ClientA;
  #endif
}
clientclass.h :-
#include "ClientA.h"
namespace my_lib {
  // you already define ClientA with typedef
  class clientClass {
    clientClass(ClientA* a);
  };
}

ClientA.h :-
namespace my_lib {
  #ifdef LEGACY_A
    #define ClientA A
  #else
    #define ClientA newA
  #endif
}
clientclass.h :-
#include "A.h"
#include "NewA.h"
#include "ClientA.h"
namespace my_lib {
  class ClientA;
  class clientClass {
    clientClass(ClientA* a);
  };
}

我只想告诉您的客户,不允许他们转发声明您的库组件并使用 typedef 方法。这对我来说似乎完全合理。

由于您的库不会一直更改,并且它已经在内部处理了任何与依赖相关的前向声明,因此它们没有理由需要通过从您的库中进行前向声明来依赖特定的内部实现。

如果您愿意,您也可以选择提供一个 <your_lib_name_fwd> header 来适当地转发声明关键组件,但我认为这不是强制性的。这有先例,例如标准库的 <iosfwd>