假设我有一个带有大型多态类层次结构的第三方库:
基本=> Sub1,Sub2,Sub3 => SubSub1,SubSub2 ...等
我可以将层次结构中各个子类的对象,* Base类型的填充指针带入STL容器中,然后使用迭代器在每个对象上调用特定的基类方法。
如果我想向基类中添加一个新的虚拟方法,然后对容器中的每个对象调用相同的方法,该怎么做?
基类是库的一部分,因此我不能仅向其添加新的虚拟方法。派生子类不起作用,因为我无法访问所有其他子类。在Java中,我将创建一个接口并让每个相关的子类实现它。不过,我不确定如何最好地使用C ++处理此问题。
编辑:
(1)下面建议的访问者模式将是一个很好的解决方案,但是要求在编写原始基类时要牢记该模式。
(2)下面建议的插件模式是可以使用的通用解决方案,但是在某些用例中可能会非常慢。
(3)从Base派生一个子类,然后重构整个层次结构,以便从该子类派生它很麻烦,并且如果升级库代码可能会破坏它。
(4)我尝试避免多重继承,但是它在我的(简单)用例中有效:
#include <third_party_lib.h>
class MyBase {
public:
virtual ~MyBase() {}
virtual void myMethod() = 0;
};
class MySub1 : public ThirdPartyLib::Sub1, MyBase {
public:
void myMethod() { /*...*/ }
};
class MySub2 : public ThirdPartyLib::Sub2, MyBase {
public:
void myMethod() { /*...*/ }
};
void doSomething() {
std::vector<ThirdPartyLib::Base*> vec;
// fill vector with instances of MySub1, MySub2, etc
for (auto libHandle : vec) {
// call a method from the library class hierarchy ...
libHandle->libraryClassMethod();
// call the virtual method declared in MyBase ...
MyBase* myHandle = dynamic_cast<MyBase*>(libHandle);
if (myHandle) {
myHandle->myMethod();
} else {
// deal with error
}
}
}
如果您没有修改基类的选项,则可以使用我称为插件模式的模式。
Base
。假设您有:
struct Shape
{
// Shape details
};
struct Triangle : public Shape
{
// Triangle details
};
struct Rectangle : public Shape
{
// Rectangle details
};
出于说明的目的,假设它Shape
没有用于计算Shape
对象面积的接口。要实现计算形状面积的功能,可以执行以下操作:
创建一个函数来获取面积Shape
。
extern double getArea(Shape const& shape);
为可以计算Shape面积的函数添加注册机制。
typedef double (*GetAreaFunction)(Shape const& shape, bool& isSuccess);
extern void registerGetAreaFunction(GetAreaFunction fun);
在.cc文件中实现核心功能。
static std::set<GetAreaFunction>& getRegistry()
{
static std::set<GetAreaFunction> registry;
return registry;
}
void registerGetAreaFunction(GetAreaFunction fun)
{
getRegistry().insert(fun);
}
double getArea(Shape const& shape)
{
double area = 0.0;
for ( auto fun: getRegistry() )
{
bool isSuccess = false;
area = fun(shape, isSuccess);
if ( isSuccess )
{
return area;
}
}
// There is no function to compute the area of the given shape.
// Throw an exception or devise another mechanism to deal with it.
}
在您的代码库中适当的地方添加函数以计算Triangle
and的面积Rectangle
。
double getArea(Triangle const& triangle)
{
// Do the needful and return the area.
}
double getArea(Rectangle const& rectangle)
{
// Do the needful and return the area.
}
添加可以在核心API中注册的功能。
double getAreaWrapper(Shape const& shape, bool& isSuccess)
{
// Do dynamic_cast to see if we can deal with the shape.
// Try Triangle first.
Triangle const* trianglePtr = dynamic_cast<Triangle const*>(&shape);
if ( trianglePtr )
{
isSuccess = true;
return getArea(*trianglePtr);
}
// Try Rectangle next.
Rectangle const* rectanglePtr = dynamic_cast<Rectangle const*>(&shape);
if ( rectanglePtr )
{
isSuccess = true;
return getArea(*rectanglePtr );
}
// Don't know how to deal with the given shape.
isSuccess = false;
return 0.0;
}
向核心注册功能。
registerGetAreaFunction(getAreaWrapper);
优点
if-else
在一个函数中出现长块的复杂方法。缺点
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句