gpt4 book ai didi

c++ - 适配器模式 : support underlying data that can be const or non-const, 优雅

转载 作者:IT老高 更新时间:2023-10-28 23:17:50 33 4
gpt4 key购买 nike

如何使适配器类适本地支持 const 和非 const 底层数据?

具体例子

RigidBody是描述对象物理属性的类。
这是其非常简化的版本(1D):-

class RigidBody{
float position=1;
public: float getPosition()const{ return position;}
public: void setPosition(float ppos){ position=ppos;}
};

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
}
};

我可以设置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;
}

一切正常 (demo)。

目标

我想创建一个接收 const 的新函数 RigidBody* rigid .
我应该能够通过使用适配器从中读取(例如 getPosition() )。

但是,我真的不知道如何优雅地做到这一点。

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
}

我的糟糕解决方案

解决方案 A1(2 个适配器 + 1 个小部件)

创建一个小部件:-

class AdapterWidget{
public: static Adapter createAdapter(RigidBody* a);
public: static AdapterConst createAdapter(const RigidBody* a);
};

AdapterConst只能getPosition() , 而 AdapterConst既可以获取也可以设置。

我可以像这样使用它:-

void test(const RigidBody* rigid){
auto adapter=AdapterWidget::createAdapter(rigid);

使用方便。

缺点:代码为AdapterConstAdapter会非常重复。

解决方案 A2(+继承)

是对之前解决方案的改进。
Adapter (有 setPosition() )派生自 AdapterConst (有 getPosition())。

缺点:不够简洁。我为单个任务使用 2 个类!
这似乎微不足道,但在更大的代码库中,它一点也不好玩。

具体来说,getPosition() 的位置将远离setPosition() ,例如在不同的文件中。
这会导致可维护性问题。

解决方案 B(模板)

创建一个模板类。有很多方法,例如:-

  • Adapter<T =RigidBody OR const RigidBody >
  • Adapter<bool=true is const OR false is non-const >

缺点:在各方面都不够优雅。这是矫枉过正。 (?)
我将遭受模板的缺点,例如标题中的所有内容。

解决方案 C1 (const_cast)

我试图避免它。 It is evil.

class Adapter{
public: RigidBody* rigid;
void setUnderlying(const RigidBody* r){
rigid=const_cast< RigidBody*>(r);
}
....
};

解决方案 C2(+手动断言)

我可以手动添加一些断言。
它只是强调它是多么不专业:-

    bool isConst;
void setUnderlying(const RigidBody* r){
...
isConst=true;
}
void setUnderlying(RigidBody* r){
...
isConst=false;
}
void setPosition(float a){
if(isConst){ /*throw some exception*/ }
....
}

方案 D(逃跑)

  • 懒惰:test( 更改 const RigidBody* 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++ 代码的极其糟糕的方式。

您的问题有一个惯用的解决方案:

  1. 抛弃大部分设计模式。它们对于默认情况下对象是引用类型的语言很有用。 C++ 大多数时候更喜欢将对象作为值类型,并且更喜欢静态多态(模板)而不是运行时多态(继承 + 覆盖)。

  2. 写两个类,一个是Adapter,一个是ConstAdapter。这就是标准库已经做的事情。正是因为这个原因,每个容器都有不同的 iteratorconst_iterator 实现。您可以通过指针存储某些东西,也可以通过 const 指针存储。尝试将两者混合使用很容易出错。如果这个问题有一个很好的解决方案,我们就不会为每个容器有两个迭代器类型定义。

关于c++ - 适配器模式 : support underlying data that can be const or non-const, 优雅,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43654534/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com