jav*_*ver 12 c++ const function adapter c++14
如何使适配器类适当地支持const和非const底层数据?
RigidBody是描述对象物理属性的类.
这是它非常简化的版本(1D): -
class RigidBody{
float position=1;
public: float getPosition()const{ return position;}
public: void setPosition(float ppos){ position=ppos;}
};
Run Code Online (Sandbox Code Playgroud)
Adapter封装RigidBody.
它提供了一个小失真的功能get/set position: -
class Adapter{
public: RigidBody* rigid; int offset=2;
public: float getPosition(){
return rigid->getPosition()+offset; //distort
}
public: void setPosition(float ppos){
return rigid->setPosition(ppos-offset); //distort
}
};
Run Code Online (Sandbox Code Playgroud)
我可以RigidBody通过以下方式间接设定位置Adapter: -
int main() {
RigidBody rigid;
Adapter adapter; //Edit: In real life, this type is a parameter of many function
adapter.rigid=&rigid;
adapter.setPosition(5);
std::cout<<adapter.getPosition();//print 5
return 0;
}
Run Code Online (Sandbox Code Playgroud)
一切正常(演示).
我想创建一个接收的新功能.
我应该能够通过使用适配器从中读取(例如). constRigidBody* rigidgetPosition()
但是,我真的不知道如何优雅地做到这一点.
void test(const RigidBody* rigid){
Adapter adapter2;
//adapter2.rigid=rigid; //not work, how to make it work?
//adapter2.setPosition(5); //should not work
//adapter2.getPosition(); //should work
}
Run Code Online (Sandbox Code Playgroud)
创建一个小部件: -
class AdapterWidget{
public: static Adapter createAdapter(RigidBody* a);
public: static AdapterConst createAdapter(const RigidBody* a);
};
Run Code Online (Sandbox Code Playgroud)
AdapterConst只能getPosition(),虽然AdapterConst可以得到和设置.
我可以像以下一样使用它: -
void test(const RigidBody* rigid){
auto adapter=AdapterWidget::createAdapter(rigid);
Run Code Online (Sandbox Code Playgroud)
它很容易使用.
缺点:代码 AdapterConst和Adapter将非常重复.
这是对以前解决方案的改进.
让Adapter(有setPosition())派生自AdapterConst(有getPosition()).
缺点:它不简洁.我为单个任务使用2个类!
这似乎是微不足道的,但在更大的代码库中,它根本不是很有趣.
具体而言,位置getPosition()将远离setPosition()例如不同的文件.
这会导致可维护性问题.
创建模板类.有很多方法,例如: -
Adapter<T =RigidBody OR const RigidBody >Adapter<bool=true is const OR false is non-const >缺点:在各方面,它都是不优雅的.这太过分了.(?)
我将遭受模板的缺点,例如标题中的所有内容.
我试图避免它. 这是邪恶的.
class Adapter{
public: RigidBody* rigid;
void setUnderlying(const RigidBody* r){
rigid=const_cast< RigidBody*>(r);
}
....
};
Run Code Online (Sandbox Code Playgroud)
我可以手动添加一些断言.
它只是强调它是多么不专业: -
bool isConst;
void setUnderlying(const RigidBody* r){
...
isConst=true;
}
void setUnderlying(RigidBody* r){
...
isConst=false;
}
void setPosition(float a){
if(isConst){ /*throw some exception*/ }
....
}
Run Code Online (Sandbox Code Playgroud)
test(constRigidBody* rigid)test(RigidBody* rigid)RigidBody::setPosition()是const. 无论哪种方式,我的程序都不会再const纠正,
但单个Adapter类就足够了.
在遇到const/non-const模式的任何地方,我真的必须做其中的一件事吗?
请提供一个漂亮的解决方案 (不需要完整的代码,但我不介意)
对不起,很长的帖子.
编辑: 在现实生活中,Adapter是许多功能的参数.
它像玩具一样传递.
大多数此类函数都没有相关知识RigidBody,因此不适合从捆绑调用更改someFunction(adapter)为someFunction(offset,rigidbody).
你不应该坚持这个想法.这是C++,而不是Java.
您的代码非常面向Java.我可以通过编写代码的方式看到它,使用指针并const在需要时静默省略.
实际上,我个人看到的大多数糟糕的C++代码都被写成"C inside classes"或"Java without GC".它们都是编写C++代码的极其糟糕的方法.
您的问题有一个惯用的解决方案:
沟渠大多数的设计模式.它们对于默认情况下对象是引用类型的语言很有用.C++倾向于大多数时候将对象作为值类型而不是静态多态(模板)而不是运行时多态(继承+覆盖).
写两个类,一个是Adapter一个,一个是ConstAdapter.这就是标准库已经完成的工作.每个容器都有不同iterator和const_iterator实现正是因为这个原因.你可以通过指针存储一些东西,或者通过const指针存储.试图将两者混合是容易出错的.如果有一个很好的解决方案,我们就不会为每个容器提供两个迭代器typedef.
使用引用而不是指针,并让常量传播到Adapter. 然后你可以安全地 const_cast,如
template <class Rigid>
class Adapter{
Rigid & rigid;
int offset;
public:
Adapter(Rigid & rigid, int offset = 2) : rigid(rigid), offset(offset) {}
float getPosition() const { return rigid.getPosition() + offset; }
void setPosition(float ppos) { rigid.setPosition(ppos - offset); }
};
Run Code Online (Sandbox Code Playgroud)