如何在拥有接口和基类的同时避免向下转换
How to avoid downcasting while having interface and base classes?
我肯定我在这里错过了一些基本的东西,但是我无法理解它。
假设我们有几个可能的Manager
类实现,它处理Base
类型的对象。应该可以定义在运行时使用哪个实现。
基于Manager
的实现,他们将不得不从Base
中设置和获得特定的属性,因此他们内部使用的衍生DerivedA
和DerivedB
。是否有一种方法可以避免在Handle
方法中向下转换参数以获得特定于实现的属性?
class Base { /* Abstract class with common properties */ };
class DerivedA : public Base { /* DerivedA-specific properties */ };
class DerivedB : public Base { /* DerivedB-specific properties */ };
class IManager { /* These functions must be implemented by every Manager implementation */
public:
virtual Base* Create() = 0;
virtual void Handle(Base*) = 0;
};
class AManager : public IManager
{
public:
Base* Create() override { return new DerivedA(); }
void Handle(Base* pFoo) override
{
// Now if we want to access pFoo's specific properties, we will need to dynamic_cast it
}
};
class BManager : public IManager
{
public:
Base* Create() override { return new DerivedB(); }
void Handle(Base* pBar) override { /* same here */ }
};
void Run(bool useAManager)
{
IManager* pManager = nullptr;
if (useAManager)
pManager = new AManager();
else
pManager = new BManager();
Base* pData = pManager->Create();
/* use Base specific properties ... */
pManager->Handle(pData);
}
编辑:谢谢大家的宝贵意见。我会接受@jpo38的帖子,因为它为这个问题提供了一个可能的解决方案。然而,经过一番考虑,我发现这个类的设计存在一个潜在的问题。
您可以使用访问者模式。在您的示例中,这将是:
class DerivedA;
class DerivedB;
class Visitor
{
public:
virtual void visitA( DerivedA& a ) = 0;
virtual void visitB( DerivedB& b ) = 0;
};
class Base
{
public:
virtual void Accept( Visitor& visitor ) = 0;
};
class DerivedA : public Base
{
public:
virtual void Accept( Visitor& visitor ) { visitor.visitA( *this ); }
};
class DerivedB : public Base
{
public:
virtual void Accept( Visitor& visitor ) { visitor.visitB( *this ); }
};
然后,从manager或BManager:
void Handle(Base* pFoo)
{
class MyVisitor : public Visitor
{
public:
virtual void visitA( DerivedA& a )
{
// do somethiong specific to a, you have access to DerivedA
}
virtual void visitB( DerivedB& b )
{
// do somethiong specific to b, you have access to DerivedB
}
};
MyVisitor v;
pFoo->Accept( v );
}
访问者模式的缺点是每次你想做一些特定的事情时,你都必须定义一个新的访问者类。
您也可以考虑这样做(但我绝对推荐访问者,如果您稍后添加DerivedC或希望通过共享访问者类共享某些特定操作,则非常有用)。
class Base
{
public:
virtual DerivedA* GetAsA() = 0;
virtual DerivedB* GetAsB() = 0;
};
class DerivedA : public Base
{
public:
virtual DerivedA* GetAsA() { return this; }
virtual DerivedB* GetAsB() { return NULL; }
};
class DerivedB : public Base
{
public:
virtual DerivedA* GetAsA() { return NULL; }
virtual DerivedB* GetAsB() { return this; }
};
然后,从manager或BManager:
void Handle(Base* pFoo)
{
if ( pFoo->GetAsA() )
{
// use GetAsA to access DerivedA object avoiding downcasting
}
if ( pFoo->GetAsB() )
{
// use GetAsB to access DerivedB object avoiding downcasting
}
}
不完全是。如果您绝对需要以不同的方式处理特定的子类型,dynamic_cast
是最干净的解决方案。
Base
参数时,您感兴趣的只是那些抽象操作。至少在完全干净的面向对象设计中,
你的类设计不是面向对象的,仅此而已。但这本身并不是问题。如果它适合您,并且代码易于阅读和维护,那么一切都很好。
相关文章:
- 防止主数据类型C++的隐式转换
- 模板参数替换失败,并且未完成隐式转换
- 努力将整数转换为链表。不知道我在这里做错了什么
- HEX值到wchar_t字符(UTF-8)的转换
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将 Qvector<uint8_t> 转换为 QString
- 如何在cuSparse中使用cusparseXcoo2csr从coo转换为csc
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 在c++中使用nlohmann从类到json的转换
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 如何使用OpenCV将RBG图像转换为HSV,并将H、S和V值保存为C++中的3个独立图像
- 复制列表初始化的隐式转换的等级是多少
- 正在将指针转换为范围
- 如何防止 c++ 在从浮点型转换为双精度型(不适用于 IO)时添加额外的小数?
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 是否可以从int转换为enum类类型
- 使用类型强制转换在单个向量中拥有不同的对象
- 如何在拥有接口和基类的同时避免向下转换