C++:向基类接口添加一个方法
C++ : Add a method to a base class interface
假设我有一个具有大型多态类层次结构的第三方库:
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
}
}
}
如果您没有修改基类的选项,您可以使用我称之为插件模式的模式。
- 在给定类型为
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
块的详细方法 - 它避免了核心中处理派生类型的硬依赖关系
缺点
- 最重要的是,不要将其用于任何需要调用数百万次的函数。这将扼杀性能
实际上有两种方法可以实现这一点。
1) 添加一个类(比如base1),它的基类将是库中的"基类"。然后让所有其他类从base1派生,而不是从base派生。
2) 使用多重继承。您添加了另一个类"base1",然后让其他派生类继承"base"answers"base1"。
我更喜欢前一种方法,因为多重继承有其自身的瓶颈。
- 不能将方法返回的值用于另一个方法
- C++有没有办法强制重写一组方法,如果其中一个方法在子类中具有重写?
- 我在C++中编写了一个方法来打印树类的预序,但它显示了分割错误
- 重写另一个方法 [C++] 使用的超类回调函数
- C++:如何使用传递引用在一个方法中返回多个值
- 为什么一个方法对同一个变量有常量和非常量参数?
- 从同一类中的另一个方法调用方法时出错
- 向现有类添加一个方法以逐行读取文件的内容
- 无法从派生的一个方法调用基类方法
- 如何将一个方法中的值返回到同一类的另一个方法
- 方法重载 C++ -> 只有一个方法调用
- 在另一个线程中执行一个方法
- 是否可以在另一个方法中使用模板类中定义的虚拟方法
- 调用方法,该方法修改字段,而使用该字段的另一个方法正在执行
- 将一个方法作为参数传递给另一个方法,该方法本身将传递的方法传递给 std 线程
- 仅专用于模板类的一个方法(部分)
- 确定一个方法是否是纯虚拟的(c++)
- 是否可以判断一个方法在编译时是否可以公开访问
- 我正在尝试创建一个方法,该方法使用指针算术返回一对,它是否会出错
- 从 ndk 中的 jni 方法调用另一个C++方法