Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 避免虚函数的标准方法_C++_Design Patterns_Virtual Functions_Typelist - Fatal编程技术网

C++ 避免虚函数的标准方法

C++ 避免虚函数的标准方法,c++,design-patterns,virtual-functions,typelist,C++,Design Patterns,Virtual Functions,Typelist,我有一个库,里面有很多小对象,现在都有虚拟函数。它达到了这样的程度:指向虚拟函数表的指针的大小可能超过对象中有用数据的大小(它通常可能只是一个包含单个浮点值的结构)。对象是稀疏图上数值模拟的元素,因此不容易合并/etc 我不太关心虚拟函数调用的成本,而是关心存储的成本。实际情况是,指向虚拟函数表的指针基本上降低了缓存的效率。我想知道我是否最好使用存储为整数的类型id,而不是虚拟函数 我不能使用静态多态性,因为我的所有对象都在一个列表中,我需要能够对由索引(这是一个运行时值-因此无法静态确定类型)

我有一个库,里面有很多小对象,现在都有虚拟函数。它达到了这样的程度:指向虚拟函数表的指针的大小可能超过对象中有用数据的大小(它通常可能只是一个包含单个
浮点值的结构)。对象是稀疏图上数值模拟的元素,因此不容易合并/etc

我不太关心虚拟函数调用的成本,而是关心存储的成本。实际情况是,指向虚拟函数表的指针基本上降低了缓存的效率。我想知道我是否最好使用存储为整数的类型id,而不是虚拟函数


我不能使用静态多态性,因为我的所有对象都在一个列表中,我需要能够对由索引(这是一个运行时值-因此无法静态确定类型)选择的项执行操作

问题是:在给定类型列表(例如,在类型列表中)和类型索引的情况下,是否有一种设计模式或通用算法可以从接口动态调用函数

接口已经定义,并且没有太大的变化,但是将来库的用户(可能不太熟练)将声明新的对象,这样做应该不需要很大的努力。表现是最重要的。遗憾的是,没有C++11

到目前为止,我可能有一个愚蠢的概念证明:

typedef MakeTypelist(ClassA, ClassB, ClassC) TList; // list of types

enum {
    num_types = 3 // number of items in TList
};

std::vector<CommonBase*> uniform_list; // pointers to the objects
std::vector<int> type_id_list; // contains type ids in range [0, num_types)

template <class Op, class L>
class Resolver { // helper class to make a list of functions
    typedef typename L::Head T;

    // specialized call to op.Op::operator ()<T>(p)
    static void Specialize(CommonBase *p, Op op)
    {
        op(*(T*)p);
    }

    // add a new item to the list of the functions
    static void BuildList(void (**function_list)(CommonBase*, Op))
    {
        *function_list = &Specialize;
        Resolver<Op, typename L::Tail>::BuildList(function_list + 1);
    }
};

template <class Op>
class Resolver<Op, TypelistEnd> { // specialization for the end of the list
    static void BuildList(void (**function_list)(CommonBase*, Op))
    {}
};

/**
 * @param[in] i is index of item
 * @param[in] op is a STL-style function object with template operator ()
 */
template <class Op>
void Resolve(size_t i, Op op)
{
    void (*function_list[num_types])(CommonBase*, Op);
    Resolver<Op, TList>::BuildList(function_list);
    // fill the list of functions using the typelist

    (*function_list[type_id_list[i]])(uniform_list[i], op);
    // call the function
}
typedef MakeTypelist(ClassA、ClassB、ClassC)TList;//类型列表
枚举{
num_types=3//t列表中的项目数
};
标准::矢量统一_列表;//指向对象的指针
std::向量类型\u id\u列表;//包含范围[0,num\u types]中的类型ID
模板
类解析器{//helper类,用于生成函数列表
typedef typename L::头T;
//对op.op::operator()的专门调用(p)
静态void专门化(CommonBase*p,Op)
{
op(*(T*)p);
}
//将新项添加到函数列表中
静态void构建列表(void(**函数列表)(CommonBase*,Op))
{
*函数列表=&专门化;
解析器::BuildList(函数列表+1);
}
};
模板
类冲突解决程序{//列表末尾的专用化
静态void构建列表(void(**函数列表)(CommonBase*,Op))
{}
};
/**
*@param[in]i是项目的索引
*@param[in]op是带有模板运算符()的STL样式函数对象
*/
模板
无效解析(大小i,Op)
{
void(*函数列表[num_类型])(CommonBase*,Op);
解析器::构建列表(函数列表);
//使用类型列表填写函数列表
(*功能列表[类型id列表[i]])(统一列表[i],op);
//调用函数
}
我还没有研究过程序集,但我相信如果是静态的,那么函数指针数组的创建实际上是免费的。另一种选择是使用类型列表上生成的二进制搜索树,这将启用内联。

是虚拟函数的编译时替代方法:

    template <class Derived> 
    struct Base
    {
        void interface()
        {
            // ...
            static_cast<Derived*>(this)->implementation();
            // ...
        }

        static void static_func()
        {
            // ...
            Derived::static_sub_func();
            // ...
        }
    };

    struct Derived : Base<Derived>
    {
        void implementation();
        static void static_sub_func();
    };
模板
结构基
{
void接口()
{
// ...
静态_cast(this)->implementation();
// ...
}
静态无效静态_func()
{
// ...
派生::static_sub_func();
// ...
}
};
派生结构:基
{
无效实现();
静态void static_sub_func();
};
它依赖于这样一个事实,即成员的定义在被调用之前不会被实例化。因此,Base应该只在其成员函数的定义中引用派生的任何成员,而不是在原型或数据成员中我在问题中概述的概念。对于每个操作,都有一个thunk表实例(它是静态的,通过模板共享-因此编译器将自动确保每个操作类型只有一个表实例,而不是每次调用).因此,我的对象没有任何虚拟功能

最重要的是-使用简单函数指针而不是虚拟函数所带来的速度增益可以忽略不计(但也不慢)。获得大量速度的是实现一个决策树并静态链接所有函数-这将一些计算量不太大的代码的运行时提高了约40%

一个有趣的副作用是能够使用“虚拟”模板函数,这通常是不可能的

我需要解决的一个问题是,我的所有对象都需要有一些接口,因为它们最终会被一些调用(而不是functor)访问。为此,我设计了一个分离的facade。facade是一个虚拟类,声明对象的接口。分离的facade是这个虚拟类的实例,专门用于given类(对于列表中的所有项目,
operator[]
返回所选项目类型的外观)

类CDetachedFacade_基{
公众:
虚虚空DoStuff(BaseType*pthis)=0;
};
模板
类CDetachedFacade:公共CDetachedFacade_库{
公众:
虚空DoStuff(基类型*pthis)
{
静态浇铸(pthis)->DoStuff();
//静态链接的CObjectType是最终类型
}
};
类CMakeFacade{
BaseType*pthis;
CDetachedFacade_Base*pfacade;
公众:
CMakeFacade(基型*p,CDetachedFacade_基*f)
:p此(p),pfacade(f)
{}
内联void DoStuff()
{
f->DoStuff(pthis);
}
};
要使用此功能,需要执行以下操作:

static CDetachedFacade<CMyObject> facade;
// this is generated and stored in a templated table
// this needs to be separate to avoid having to call operator new all the time

CMyObject myobj;
myobj.DoStuff(); // statically linked

BaseType *obj = &myobj;
//obj->DoStuff(); // can't do, BaseType does not have virtual functions

CMakeFacade obj_facade(obj, &facade); // choose facade based on type id
obj_facade.DoStuff(); // calls CMyObject::DoStuff()
静态CDetachedFacade立面;
//这将生成并存储在模板表中
//这需要分开,以避免必须随时呼叫新操作员
CmyObjectMyObj;
myobj.DoStuff();//静态链接
BaseType*obj=&myobj;
//obj->DoS
static CDetachedFacade<CMyObject> facade;
// this is generated and stored in a templated table
// this needs to be separate to avoid having to call operator new all the time

CMyObject myobj;
myobj.DoStuff(); // statically linked

BaseType *obj = &myobj;
//obj->DoStuff(); // can't do, BaseType does not have virtual functions

CMakeFacade obj_facade(obj, &facade); // choose facade based on type id
obj_facade.DoStuff(); // calls CMyObject::DoStuff()