C++ 根据枚举值指定子函数

C++ 根据枚举值指定子函数

问题描述

我想要对一幅图像实现一个算法,并根据算法类型传递参数给这个算法。 (例如,我可能想要在串行或并行中计算一个曼德勃罗特集,但两种实现都使用相同的参数)。

所以,这里是表示分形类型的枚举: (我有意省略了 #include#pragmas 等…)

enum class FractalType
{
    Mandelbrot,
    SomeOtherFractal
};

我的摘要 FractalGenerator 类:

template <FractalType FT>
class
    FractalGenerator
{
public:
    virtual int computeFractal(Mat m, FractalParameters<FT> *fp) = 0;
};

一个用于曼德博集合参数的派生结构 MandelBrotParameters

struct MandelBrotParameters : FractalParameters<FractalType::Mandelbrot>
{
    /* data */
};

这个类的实现还包括了一个用于Mandelbrot的实现:

MandelBrotSerial :

class MandelbrotSerial : public FractalGenerator<FractalType::Mandelbrot>
{
public:
    int computeFractal(Mat m, MandelBrotParameters *fp);
};

但是函数 MandelbrotSerial::computeFractal 没有覆盖其父抽象函数。

我该怎么解决这个问题?

解决方案

如果你的目标是使代码调用 computeFractal() 而不需要特定于特定的分形类型,你可以通过一个抽象的、非模板的基类来实现这一目标,用于你的各种参数类:

struct AbstractFractalParameters
{
   // empty
}

template<typename T> struct FractalParameters<T> : public AbstractFractalParameters
{
    // ...
}

template <FractalType FT> class FractalGenerator
{
public:
   virtual int computeFractal(Mat m, AbstractFractalParameters *fp) = 0;
};

void SomeCallingCode(FractalGenerator * g, Mat m, AbstractFractalParameters * p)
{
   g->computeFractal(m, p);  // works, as long as (p) is pointing to the correct subclass for (g)
}

然后,您的computeFractal()实现可以将接收到的AbstractFractalParameter *指针向下转换为预期的特定于实现的子类类型。

当然,以这种方式执行有点危险,因为您依赖于调用代码传递指向正确类型的参数对象的指针;如果调用者弄错了,您要么需要处理错误条件(如果您的computeFractal()实现使用dynamic_cast<>),要么将出现未定义的行为(如果您的computeFractal()实现使用static_cast<>)。

您可能最好完全使用模板化的代码,完全避免虚方法/运行时多态。这意味着所有调用computeFractal()的与分形类型无关的代码也需要进行模板化,不过是否是问题取决于您有多少调用代码以及其功能。

例如,注意下面的callComputeFractal()函数演示了编译时多态,即main()(或任何人)可以以不同的生成器类型(在编译时指定)调用它,它将适用于任何类型。

#include <stdio.h>

class MandelbrotFractalGenerator;
class OtherFractalGenerator;

template<typename GenType> struct FractalParameters {};

// parameters appropriate for the mandelbrot generator
template<> struct FractalParameters<MandelbrotFractalGenerator>
{
   FractalParameters(float p1, float p2) : mandelParam1(p1), mandelParam2(p2) {/* empty */}

   float mandelParam1;
   float mandelParam2;
};

// parameters appropriate for the other generator
template<> struct FractalParameters<OtherFractalGenerator>
{
   FractalParameters(int p1, int p2) : otherParam1(p1), otherParam2(p2) {/* empty */}

   int otherParam1;
   int otherParam2;
};

class MandelbrotFractalGenerator
{
public:
   MandelbrotFractalGenerator() {/* empty */}

   int computeFractal(const FractalParameters<MandelbrotFractalGenerator> &fp)
   {
      printf("MandelbrotFractalGenerator::computeFractal mandelParam1=%f mandelParam2=%f\n", fp.mandelParam1, fp.mandelParam2);
      return 0;
   }
};

class OtherFractalGenerator
{
public:
   OtherFractalGenerator() {/* empty */}

   int computeFractal(const FractalParameters<OtherFractalGenerator> &fp)
   {
      printf("OtherFractalGenerator::computeFractal otherParam1=%i otherParam2=%i\n", fp.otherParam1, fp.otherParam2);
      return 0;
   }
};

// Example of a generator-type-agnostic templated function that can call methods on any generator-type
template<class FractalGeneratorType>
void callComputeFractal(FractalGeneratorType & generator, const FractalParameters<FractalGeneratorType> & params)
{
   generator.computeFractal(params);
}

int main(int, char **)
{
   MandelbrotFractalGenerator mandelbrotGen;
   OtherFractalGenerator otherGen;

   callComputeFractal<>(mandelbrotGen, FractalParameters<MandelbrotFractalGenerator>(1.0f, 2.0f));
   callComputeFractal<>(otherGen, FractalParameters<OtherFractalGenerator>(3, 4));

   return 0;
}

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程