为了确保保持ABI,我使用带有显式vtable的类。

在myinterface / import.h中

class MyInterface
    {
    public:
        void doStuff()
            {m_vt->doStuff(this);}

        class Vtable
            {
            friend class MyInterface;
            public:
                bool init(void* module);
                size_t abiVersionTagGet() const
                     {return abi_version_tag;}

            private:
                typedef void (*DoStuffFunc)(MyInterface* obj);
                size_t abi_version_tag;
                DoStuffFunc doStuff;
            //etc
            };
    private:
         Vtable* m_vt;
    };

vtable内的函数指针是指动态库,其导出函数如

在myinterface / export.h中:
 class MyInterface;

 extern "C"
     {
     void EXPORT MyInterface_1doStuff(MyInterface* object);
     }

在myinterfaceimpl.cpp(或所谓的名称)中
 #include "myinterface/export.h"

 void MyInterface_1doStuff(MyInterface* object)
      {
      MyInterfaceImpl* _this=(MyInterfaceImpl*)object;
      // ...
      }

现在,我为每个接口(interface)维护了2个包含文件。如何使维护此类结构更容易。

编辑:下面的Pimpl“解决方案”不能解决问题,因为它也依赖于自动vtable。

最佳答案

根据注释的要求,下面是一个使用宏半途到达的示例。

在我开始之前,缺点是:

  • 与任何预处理程序破解一样,这很丑陋。
  • 我使用了GCC的swallow-the-逗号扩展名;
  • 这不会自动找出修饰的函数调用(尤其是因为这将取决于编译器);
  • 这可能无法与IDE的intellisense配合使用,并且会使开发人员更难找到函数原型(prototype)(除非在分发前先用gcc -E扩展头。如果这样做,则应将循环宏修改为包括结尾的换行符)。

  • 因此,让我们从丑陋开始。将其隐藏在标题中(我尝试过使用可以在其他地方重用的函数);
    #define EXPAND(a) a
    #define ARGS_COUNT__(\
    _96,_95,_94,_93,_92,_91,_90,_89,_88,_87,_86,_85,_84,_83,_82,_81,\
    _80,_79,_78,_77,_76,_75,_74,_73,_72,_71,_70,_69,_68,_67,_66,_65,\
    _64,_63,_62,_61,_60,_59,_58,_57,_56,_55,_54,_53,_52,_51,_50,_49,\
    _48,_47,_46,_45,_44,_43,_42,_41,_40,_39,_38,_37,_36,_35,_34,_33,\
    _32,_31,_30,_29,_28,_27,_26,_25,_24,_23,_22,_21,_20,_19,_18,_17,\
    _16,_15,_14,_13,_12,_11,_10, _9, _8, _7, _6, _5, _4, _3, _2, _1,\
    N,...) N
    #define ARGS_COUNT_(...) ARGS_COUNT__(__VA_ARGS__,\
    96,95,94,93,92,91,90,89,88,87,86,85,84,83,82,81,\
    80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,\
    64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,\
    48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,\
    32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,\
    16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
    #define ARGS_HEAD(a,...) a
    #define ARGS_TAIL(a,...) (__VA_ARGS__)
    
    #define FOREACH(macro,list) FOREACH_(ARGS_COUNT_ list,macro,list)
    #define FOREACH_(n,macro,list) FOREACH__(n,macro,list)
    #define FOREACH__(n,macro,list) FOREACH_##n(macro,list)
    #define FOREACH_1(macro,list) EXPAND(macro EXPAND list)
    #define FOREACH_2(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_1(macro,ARGS_TAIL list)
    #define FOREACH_3(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_2(macro,ARGS_TAIL list)
    #define FOREACH_4(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_3(macro,ARGS_TAIL list)
    #define FOREACH_5(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_4(macro,ARGS_TAIL list)
    #define FOREACH_6(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_5(macro,ARGS_TAIL list)
    #define FOREACH_7(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_6(macro,ARGS_TAIL list)
    #define FOREACH_8(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_7(macro,ARGS_TAIL list)
    #define FOREACH_9(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_8(macro,ARGS_TAIL list)
    #define FOREACH_10(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_9(macro,ARGS_TAIL list)
    #define FOREACH_11(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_10(macro,ARGS_TAIL list)
    #define FOREACH_12(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_11(macro,ARGS_TAIL list)
    #define FOREACH_13(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_12(macro,ARGS_TAIL list)
    #define FOREACH_14(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_13(macro,ARGS_TAIL list)
    #define FOREACH_15(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_14(macro,ARGS_TAIL list)
    #define FOREACH_16(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_15(macro,ARGS_TAIL list)
    #define FOREACH_17(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_16(macro,ARGS_TAIL list)
    #define FOREACH_18(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_17(macro,ARGS_TAIL list)
    #define FOREACH_19(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_18(macro,ARGS_TAIL list)
    #define FOREACH_20(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_19(macro,ARGS_TAIL list)
    #define FOREACH_21(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_20(macro,ARGS_TAIL list)
    #define FOREACH_22(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_21(macro,ARGS_TAIL list)
    #define FOREACH_23(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_22(macro,ARGS_TAIL list)
    #define FOREACH_24(macro,list) EXPAND(macro ARGS_HEAD list) FOREACH_23(macro,ARGS_TAIL list)
    // etc. You need to repeat this up to the maximum number of loops you will need.
    // maybe somebody can find a way to split the list in half, in which case
    // the number of these would be dramatically reduced (n -> log_2(n))
    

    那是什么顾名思义,ARGS_COUNT_东西确实可以做到;它计算您提供了多少个参数。由FOREACH函数使用,它的用法如下:
    #define MY_MACRO(a,b,c) int t##a = b + c;
    FOREACH( MY_MACRO, ((1,2,3),(4,5,6)) )
    

    (注意参数周围的所有括号)。那会产生:
    int t1 = 2 + 3;
    int t4 = 5 + 6;
    

    凉。

    因此,让我们将其用于您正在做的事情。首先,我们将列出重要部分:(这应该放在两个 header 都包含的 header 中)
    // return type, function name, function parameters, parameter pass-through
    #define MY_FUNCTIONS ( \
      (void, doStuff, _1doStuff, (), ()), \
      (int, someOtherFunction, _1someOtherFunction, (int a, float b), (a,b)) \
    )
    

    我们需要重复带有和不带有类型的参数,这有点丑陋,但是我想不出一个整洁的选择。

    所以现在循环:
    class MyInterface {
    public:
    #define ADD_THIS(...) (this,##__VA_ARGS__)
    #define MY_PASSTHROUGH(ret,name,fancy,args,pass) ret name args{m_vt->name ADD_THIS pass;}
        FOREACH(MY_PASSTHROUGH,MY_FUNCTIONS)
    
        class Vtable {
            // ...
        private:
            size_t abi_version_tag;
    #define ADD_THIS_P(...) (MyInterface*,##__VA_ARGS__)
    #define MY_FUNCDEF(ret,name,fancy,args,pass) typedef ret (*name##Func)ADD_THIS_P args; name##Func name;
            FOREACH(MY_FUNCDEF,MY_FUNCTIONS)
        };
    private:
         Vtable* m_vt;
    };
    

    在另一个标题中:
    class MyInterface;
    extern "C" {
    #define ADD_THIS_P(...) (MyInterface*,##__VA_ARGS__)
    #define MY_CFUNC(ret,name,fancy,args,pass) ret EXPORT MyInterface##fancy ADD_THIS_P args;
        FOREACH(MY_CFUNC,MY_FUNCTIONS)
    }
    

    关于c++ - 双接口(interface)规范,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16120119/

    10-13 09:47