C ++:向基类接口添加方法

mdtsandman

假设我有一个带有大型多态类层次结构的第三方库:

基本=> 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
    }
  }  
}
萨胡

如果您没有修改基类的选项,则可以使用我称为插件模式的模式。

  1. 给定类型的对象,您可以创建全局函数或在适当的命名空间中创建函数来执行操作Base
  2. 您提供一种机制,派生类型的实现可以在其中注册自己。
  3. 在函数的实现中,您遍历已注册的函数/函数以检查对象类型是否存在实现。是,执行操作。否则,您将报告一个错误。

假设您有:

struct Shape
{
    // Shape details
};

struct Triangle : public Shape
{
    // Triangle details
};

struct Rectangle : public Shape
{
    // Rectangle details
}; 

出于说明的目的,假设它Shape没有用于计算Shape对象面积的接口要实现计算形状面积的功能,可以执行以下操作:

  1. 创建一个函数来获取面积Shape

    extern double getArea(Shape const& shape);
    
  2. 为可以计算Shape面积的函数添加注册机制。

    typedef double (*GetAreaFunction)(Shape const& shape, bool& isSuccess);
    
    extern void registerGetAreaFunction(GetAreaFunction fun);
    
  3. 在.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.
    }
    
  4. 在您的代码库中适当的地方添加函数以计算Triangleand的面积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.
    }
    
  5. 添加可以在核心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;            
    }
    
  6. 向核心注册功能。

    registerGetAreaFunction(getAreaWrapper);
    

优点

  1. 这是一种避免if-else在一个函数中出现长的复杂方法
  2. 它避免了核心中的硬依赖性来处理派生类型。

缺点

  1. 最重要的是-不要将此函数用于任何需要调用数百万次的函数。那会降低性能。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在基类中声明的C#接口方法无需在派生类中再次实现

来自分类Dev

防止在派生类C#中调用基类实现的接口方法

来自分类Dev

在基类中声明的C#接口方法无需在派生类中再次实现

来自分类Dev

C#:我的派生类无法覆盖基类的接口方法实现,为什么?

来自分类Dev

c ++-通过抽象模板基类接口指针访问派生类方法,而接口中没有显式类型

来自分类Dev

C ++ /任何OOP语言:向现有类添加方法而无需进行类内声明

来自分类Dev

C ++类添加方法

来自分类Dev

在运行时向类添加Objective-C方法

来自分类Dev

在运行时向类添加Objective-C方法

来自分类Dev

替换C ++基类方法?

来自分类Dev

通过接口向转换器类添加方法

来自分类Dev

在C ++模板特化中添加基类

来自分类Dev

C ++国际象棋的接口基类数组

来自分类Dev

基类和接口的 C# 通用约束

来自分类Dev

C ++类方法前向声明

来自分类Dev

您能否将派生类添加到其基类的列表中,然后从C#中的基类列表中调用派生类的方法

来自分类Dev

c ++类实现接口,接口具有采用实现该接口的任何类的方法

来自分类Dev

向EditorFor中添加类-razor C#

来自分类Dev

向类添加方法

来自分类Dev

如何向EF6自动生成的模型添加基类/接口

来自分类Dev

CLI / C ++接口类,泛型方法调用模板方法

来自分类Dev

CLI / C ++接口类,通用方法调用模板方法

来自分类Dev

C ++调用基类方法slices对象

来自分类Dev

从基类C#调用子类方法

来自分类Dev

向所有类添加接口

来自分类Dev

将具有基类的抽象类转换为接口C#

来自分类Dev

将具有基类的抽象类转换为接口C#

来自分类Dev

c ++在向继承树的某些类引入附加接口时避免代码重复

来自分类Dev

在C ++中基于接口强制类中的静态方法

Related 相关文章

  1. 1

    在基类中声明的C#接口方法无需在派生类中再次实现

  2. 2

    防止在派生类C#中调用基类实现的接口方法

  3. 3

    在基类中声明的C#接口方法无需在派生类中再次实现

  4. 4

    C#:我的派生类无法覆盖基类的接口方法实现,为什么?

  5. 5

    c ++-通过抽象模板基类接口指针访问派生类方法,而接口中没有显式类型

  6. 6

    C ++ /任何OOP语言:向现有类添加方法而无需进行类内声明

  7. 7

    C ++类添加方法

  8. 8

    在运行时向类添加Objective-C方法

  9. 9

    在运行时向类添加Objective-C方法

  10. 10

    替换C ++基类方法?

  11. 11

    通过接口向转换器类添加方法

  12. 12

    在C ++模板特化中添加基类

  13. 13

    C ++国际象棋的接口基类数组

  14. 14

    基类和接口的 C# 通用约束

  15. 15

    C ++类方法前向声明

  16. 16

    您能否将派生类添加到其基类的列表中,然后从C#中的基类列表中调用派生类的方法

  17. 17

    c ++类实现接口,接口具有采用实现该接口的任何类的方法

  18. 18

    向EditorFor中添加类-razor C#

  19. 19

    向类添加方法

  20. 20

    如何向EF6自动生成的模型添加基类/接口

  21. 21

    CLI / C ++接口类,泛型方法调用模板方法

  22. 22

    CLI / C ++接口类,通用方法调用模板方法

  23. 23

    C ++调用基类方法slices对象

  24. 24

    从基类C#调用子类方法

  25. 25

    向所有类添加接口

  26. 26

    将具有基类的抽象类转换为接口C#

  27. 27

    将具有基类的抽象类转换为接口C#

  28. 28

    c ++在向继承树的某些类引入附加接口时避免代码重复

  29. 29

    在C ++中基于接口强制类中的静态方法

热门标签

归档