假设我有一个具有大型多态类层次结构的第三方库:
Base => 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
}
}
}
答案 0 :(得分:2)
实际上有两种方法可以实现这一目标。
1)添加一个类(比如base1),其中base将是库中的“基类”。然后让所有其他类派生自base1而不是base。
2)使用多重继承。你添加另一个类“base1”,然后让其他派生类继承“base”和“base1”。
我更喜欢以前的方法,因为多重继承有它自己的瓶颈。
答案 1 :(得分:1)
如果您没有修改基类的选项,可以使用我称之为插件模式的模式。
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);
为可以计算形状区域的函数添加注册机制。
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
和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
块的复杂方法。<强>缺点强>