【问题标题】:C++ Defining a virtual base class overloaded operatorC++ 定义一个虚拟基类重载运算符
【发布时间】:2013-07-04 01:13:10
【问题描述】:

我正在尝试编写一组通用数学实用程序类(根查找器、积分器等),它们在构造一个指向基类的指针时接受,该基类定义了我希望特定算法对其进行操作的函数。基类应该只定义一个公共虚拟接口(抽象或具有默认琐碎功能)type operator()(type inputArg),用户可以根据需要实现该接口。这将允许用户只实现所需的函子并执行所需的计算。我的mwe如下:

第一个头文件定义了抽象接口类

// BaseFunctor.h

#ifndef _BASE_FUNCTOR_H_
#define _BASE_FUNCTOR_H_

class BaseFunctor
{
public:
   virtual double operator() (double x) = 0;
};
#endif

这是求解器方法之一的类

// NewtonsMethod.h

#ifndef _NEWTONS_METHOD_H_
#define _NEWTONS_METHOD_H_

class BaseFunctor;

class NewtonsMethod
{
public: 

   NewtonsMethod(BaseFunctor *rhsIn,
                 BaseFunctor *rhsPrimeIn,
                 double       x0In);

   ~NewtonsMethod();

   bool DetermineRoot(double &root);

 private:

   double       x0;
   BaseFunctor *rhs;
   BaseFunctor *rhsPrime;

   static const double       EPSILON;
   static const unsigned int MAX_ITER;

};
#endif

这是求解器的实现: // NewtonsMethod.cpp

#include "NewtonsMethod.h"
#include "BaseFunctor.h"
#include <cmath>

const double       NewtonsMethod::EPSILON  = 1e-9;
const unsigned int NewtonsMethod::MAX_ITER = 30;

NewtonsMethod::NewtonsMethod(BaseFunctor *rhsIn,
                             BaseFunctor *rhsPrimeIn,
                             double       x0In) :
   rhs     (rhsIn),
   rhsPrime(rhsPrimeIn),
   x0      (x0In)
{ }

NewtonsMethod::~NewtonsMethod() { }

bool NewtonsMethod::DetermineRoot(double &root)
{
   // This is obviously not implemented
   root = rhs(1.0) / rhsPrime(2.0);
   return false;
}

以及我进行派生类实现的主要功能: // Main.cpp

#include "BaseFunctor.h"
#include "NewtonsMethod.h"
#include <iostream>
#include <iomanip>

class fOfX : public BaseFunctor
{
   double operator() (double x)
   {
      return x * x - 2.0;
   }
};

class fPrimeOfX : public BaseFunctor
{
   double operator() (double x)
   {
      return 2.0 * x;
   }
};


int main()
{
   double x0 = 2.0;

   BaseFunctor *f      = new fOfX();
   BaseFunctor *fPrime = new fPrimeOfX(); 

   NewtonsMethod newton(f, fPrime, x0);

   double root      = 0.0;
   bool   converged = newton.DetermineRoot(root);

   if (converged)
   {
      std::cout << "SUCCESS: root == " << std::setprecision(16) << root << std::endl;
   }
   else
   {
      std::cout << "FAILED: root == " << std::setprecision(16) << root << std::endl;
   }
   delete f;
   delete fPrime;
}

我尽量简短,如果太长,请见谅。基本上我得到了错误:

g++ Main.cpp NewtonsMethod.cpp -o main
NewtonsMethod.cpp: In member function ‘bool NewtonsMethod::DetermineRoot(double&)’: 
NewtonsMethod.cpp:29: error: ‘((NewtonsMethod*)this)->NewtonsMethod::rhs’ cannot be used    as a function
NewtonsMethod.cpp:29: error: ‘((NewtonsMethod*)this)->NewtonsMethod::rhsPrime’ cannot be   used as a function

我怎样才能解决这个问题,保留所需的功能或为各种需要的功能派生一个类?

谢谢

【问题讨论】:

    标签: c++ operator-overloading functor


    【解决方案1】:

    rhsrhsPrime 是指针。您需要引用它们才能调用函数调用运算符。

    (*rhs)(1.0) / (*rhsPrime)(2.0)
    

    如果rhsrhsPrime 是必需的(即不能为NULL)并且在NewtonsMethod 对象具有构造函数后无法更改,则应将它们声明为引用而不是指针。这也将消除取消引用它们以调用函数调用运算符的需要。

    下面的例子展示了如何使用引用来引用函子。

    class NewtonsMethod
    {
    public: 
       NewtonsMethod(BaseFunctor& rhsIn,
                     BaseFunctor& rhsPrimeIn,
                     double       x0In);
    
       ~NewtonsMethod();
    
       bool DetermineRoot(double &root);
    
     private:
    
       double       x0;
       BaseFunctor& rhs;
       BaseFunctor& rhsPrime;
    
       static const double       EPSILON;
       static const unsigned int MAX_ITER;
    };
    
    int main()
    {
       double x0 = 2.0;
    
       fOfX       f;
       fPrimeOfX  fPrime;
    
       NewtonsMethod newton(f, fPrime, x0);
    }
    

    ...或...

    int main()
    {
       double x0 = 2.0;
    
       BaseFunctor *f      = new fOfX();
       BaseFunctor *fPrime = new fPrimeOfX(); 
    
       NewtonsMethod newton(*f, *fPrime, x0);
    
       // ... other code including delete for the functors
    }
    

    【讨论】:

    • 谢谢!取消引用它们是有效的,尽管它是一个丑陋的解决方案。由于我将它们称为 BaseClass 对象,如何将它们作为参考?我不能在 main 中静态分配它们,对吗?
    • 我更新了我的答案以包含一个使用参考的示例。当然,您仍然需要确保仿函数对象的生命周期等于或大于 NewtonsMethod 对象。
    • 非常感谢您的澄清。我从来没有一个类将静态创建的对象的引用保存为成员变量(只有指针(或值......))。这可以按需要工作,并且比取消引用和新 / 删除更干净。
    • 不客气。如果您还不熟悉生命周期和所有权的主题,我建议您开始深入研究它。例如,您可以使用std::vector 而不是新/删除char 缓冲区。其他时候 std::unique_ptrstd::shared_ptr 应该在您使用 new 创建对象时尽可能使用。 SO上有大量关于此的资源;)
    • 我错过了原始帖子中删除的粘贴(现已更新)。我熟悉共享指针和对象所有权,但还没有跳到 C++11,所以我还不能充分利用其中的一些特性。不过,我在 valgrind 方面做得很好;)
    猜你喜欢
    • 2021-11-12
    • 1970-01-01
    • 2011-09-08
    • 2018-12-01
    • 2019-10-21
    • 2020-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多