【发布时间】:2017-08-22 03:38:35
【问题描述】:
如何创建许多类来充当接口类的实现者,同时尽可能避免 v-table 开销,并且仍然启用对接口的静态转换?
对于一个简单的情况,可以像下面的例子那样实现。
示例
库代码 :-
class I{ //interface
public: virtual void i1()=0;
};
template<class Derived>class Router : public I{
public: virtual void i1()final{
//in real case it is very complex, but in the core is calling :-
static_cast<Derived*>(this)->u1();
}
};
用户代码:-
class User : public Router<User>{
public: void u1(){ std::cout<<"hi"<<std::endl; }
};
int main() {
User u;
u.i1(); //<-- no v-table cost
I* i=&u;
i->i1(); //<-- has v-table cost (OK)
}
问题
以下代码无法编译,但它描绘了我的梦想。 (full demo)。
库代码 :-
class I{ //interface
public: virtual void i1()=0;
public: virtual void i2()=0;
};
template<class Derived>class RouterI1U1 : public I{
public: virtual void i1()final{ static_cast<Derived*>(this)->u1(); }
};
template<class Derived>class RouterI1U2 : public I{
public: virtual void i1()final{ static_cast<Derived*>(this)->u2(); }
};
template<class Derived>class RouterI2U1 : public I{
public: virtual void i2()final{ static_cast<Derived*>(this)->u1(); }
};
template<class Derived>class RouterI2U2 : public I{
public: virtual void i2()final{ static_cast<Derived*>(this)->u2(); }
};
用户代码:-
想要使用上述库的人,可以轻松选择任何他想要的“路线”。
- 派生自
RouterI1U2<User>和RouterI2U1<User>或 - 派生自
RouterI1U1<User>和RouterI2U2<User>或 - 派生自 {
RouterI1U1<User>或RouterI1U2<User>} 并使用 final 手动实现i2()或 - 派生自 {
RouterI2U2<User>或RouterI2U1<User>} 并使用 final 手动实现i1()或 - 使用 final 手动实现
i1()和i2()
这是一个梦寐以求的用法示例。
class User : public RouterI1U2<User>,public RouterI2U1<User>{
public: void u1(){ std::cout<<"hi1"<<std::endl; }
public: void u2(){ std::cout<<"hi2"<<std::endl; }
};
int main() {
User u;
u.i1(); //<-- no v-table cost
I* i=&u;
i->i1(); //<-- has v-table cost (OK)
}
我的糟糕解决方案
class I{ //interface
public: virtual void i1()=0;
public: virtual void i2()=0;
};
template<class Derived> class RouterI1U2_I2U1 : public I{ //group it
public: virtual void i1()final{ static_cast<Derived*>(this)->u2(); }
public: virtual void i2()final{ static_cast<Derived*>(this)->u1(); }
};
class User : public RouterI1U2_I2U1<User>{
public: void u1(){ std::cout<<"hi1"<<std::endl; }
public: void u2(){ std::cout<<"hi2"<<std::endl; }
};
它可以工作 (demo),但提供的模块化程度较低。 (低可重用性)
我必须手动将RouterI1U2 和RouterI2U1 打包到RouterI1U2_I2U1。
【问题讨论】:
标签: c++ interface c++14 crtp vtable