如何在返回对象C ++时更改返回的对象基类的函数的实现

时间:2010-09-19 15:57:50

标签: c++ inheritance reference virtual return

我在C ++中有一个现有的应用程序,它有一个自定义ArrayBase类,用于管理存储和访问连续分配的内存区域。我有一个单独的ItrBase类,用于访问ArrayBase中的数据。 ArrayBase有一个createItr()函数,当前返回ItrBase个对象。

我需要扩展ArrayBase以使用多个内存分配而不是一个连续内存分配。我创建了一个EnhancedArray类来做到这一点。为使此EnhancedArray与现有应用程序兼容,它的createItr()函数必须返回适用于新的多内存分配的内容。

所以,我已经创建了一个派生的EnhanceItr类来执行此操作。 我的问题是我无法找到像这样的数百个代码出现的方法:

ItrBase anIterator = anArray.createItr();
...
double x = anIterator.getData();

EhancedItrgetData()时使用anArray的{​​{1}}功能。

这是一个简单的应用程序,说明了我的基本安排。

EnhancedArray

当我希望第二次调用返回0时,对#include <iostream> using namespace std; class ItrBase { public: ItrBase() { cout << "ItrBase constructor.\n"; }; ~ItrBase() { cout << "ItrBase destructor.\n"; }; virtual int vfunc() {return 1;}; }; class EnhancedItr : public ItrBase { public: EnhancedItr() { cout << "EnhancedItr constructor.\n"; }; ~EnhancedItr() { cout << "EnhancedItr destructor.\n"; }; int vfunc() {return 0;}; }; class ArrayBase { public: ArrayBase() { cout << "ArrayBase constructor.\n"; }; ~ArrayBase() { cout << "ArrayBase destructor.\n"; }; virtual ItrBase & createItr() {cout << "in AB's createItr()\n"; return *new ItrBase(); }; }; class EnhancedArray : public ArrayBase { public: EnhancedArray() { cout << "EnhancedArray constructor.\n"; }; ~EnhancedArray() { cout << "EnhancedArray destructor.\n"; }; EnhancedItr & createItr() {cout << "in EA's createItr()\n"; return *new EnhancedItr(); }; }; int main() { ArrayBase ab; EnhancedArray ea; ItrBase itr = ab.createItr(); ItrBase eitr = ea.createItr(); //EnhancedItr assigned to ItrBase cout << "ArrayBase's Itr .vfunc(): " << itr.vfunc() <<std::endl; cout << "EnhancedArray's Itr .vfunc(): " << eitr.vfunc() <<std::endl; return 0; } 的两次调用都返回1。

vfunc()中,我知道如果我将main()类型更改为ItrBase,我会获得所需的返回类型,但之后我正在修改“现有”代码在数百个区域中,并没有调用迭代器的析构函数。

我还没有看到另一种策略吗?

感谢。

4 个答案:

答案 0 :(得分:2)

当然,如果允许您重写ItrBase,那么您可以使用委托将所有函数调用传递给实现类,该实现类由指针或引用保存,以便多态性生效。这看起来很像 pimpl 。并且根本不需要编写调用者,只需重新编译。

编辑:那些不熟悉pimpl的人的代码。

struct ItrBase
{
  struct ItrImpl
  {
    virtual ~ItrImpl(){}
    virtual int vfunc() = 0;
  };

  ItrBase(ItrImpl peer) : m_peer(peer) { cout << "ItrBase constructor.\n"; }
  ~ItrBase() { cout << "ItrBase destructor.\n"; }
  int vfunc() { return m_peer->vfunc(); }
private:
  const unique_ptr<ItrImpl> m_peer;
};

class ArrayBase
{
  struct ItrImpl : public ItrBase::ItrImpl
  {
    virtual int vfunc() { return 0; }
  };

public:
  ArrayBase() { cout << "ArrayBase constructor.\n"; };
  ~ArrayBase() { cout << "ArrayBase destructor.\n"; };
  virtual ItrBase createItr() { cout << "in AB's createItr()\n"; return ItrBase(new ItrImpl); };
};

class EnhancedArray : public ArrayBase
{
  struct ItrImpl : public ItrBase::ItrImpl
  {
    virtual int vfunc() { return 1; }
  };

public:
  EnhancedArray() { cout << "EnhancedArray constructor.\n"; };
  ~EnhancedArray() { cout << "EnhancedArray destructor.\n"; };
  virtual ItrBase createItr() { cout << "in EA's createItr()\n"; return ItrBase(new ItrImpl); };
};

答案 1 :(得分:0)

您遇到了一个名为slicing的问题:createItr会返回一个引用,然后您将其复制到ItrBase 按值 。就像你做了这样的事情:

EnhancedItr itr1 = ...;
BaseItr itr2 = itr1;  // copy by-value
cout << itr2.vfunc();  // prints 1, not 0

你也在泄漏内存:createItr返回一个新分配的对象,但你永远不会删除它。这非常糟糕,特别是因为您希望频繁使用数组迭代器。

答案 2 :(得分:0)

你可以做的完全不同的是使用,

BOOST_AUTO(iterator, array);

让编译器找出返回类型。

BOOST_AUTO

答案 3 :(得分:0)

不与标准库保持同步,我无法使用Ben Voigt建议的unique_ptr<>实施。 (版本&gt; = 4.3)我相信我已经采用了他的概念并用基本指针实现了它。但请注意,此实现不是异常安全的。 ItrImpl个对象可能会被取消删除。

这是我的代码。太糟糕了createItr()必须返回ItrBase对象而不是指针,否则我认为我可以让auto_ptr<>工作。程序执行期间的输出显示~ItrBase()仅为每个实例调用一次,但我很惊讶在从createItr()返回对象期间也没有调用它。返回值优化?

#include <iostream>
using namespace std;

struct ItrBase
{
    struct ItrImpl
    {
        virtual ~ItrImpl(){};
        virtual int vfunc() const = 0;
    };
    ItrBase(ItrImpl* peer) : m_peer(peer) { cout << "ItrBase constructor.\n"; };
    ~ItrBase() { cout << "ItrBase destructor. \n"; delete m_peer; };
    int getData() const { return m_peer->vfunc(); };

private:
    ItrImpl* const  m_peer;
};

class ArrayBase
{
    struct ItrImpl : public ItrBase::ItrImpl
    {
        virtual int vfunc() const { return 0; };
    };

public:
    ArrayBase() { cout << "ArrayBase constructor.\n"; };
    ~ArrayBase() { cout << "ArrayBase destructor.\n"; };
    virtual ItrBase createItr() { cout << "in AB's createItr()\n"; return ItrBase(new ItrImpl); };
};

class EnhancedArray : public ArrayBase
{
    struct ItrImpl : public ItrBase::ItrImpl
    {
        virtual int vfunc() const { return 1; };
    };

public:
    EnhancedArray() { cout << "EnhancedArray constructor.\n"; };
    ~EnhancedArray() { cout << "EnhancedArray destructor.\n"; };
    virtual ItrBase createItr() { cout << "in EA's createItr()\n"; return ItrBase(new ItrImpl); };
};

int main()
{
    ArrayBase ab;
    EnhancedArray ea;

    ItrBase itr = ab.createItr();  
    ItrBase eitr = ea.createItr();  //EnhancedItr assigned to ItrBase


    cout << "ArrayBase's Itr .vfunc(): " << itr.getData() <<std::endl;
    cout << "EnhancedArray's Itr .vfunc(): " << eitr.getData() <<std::endl;

    return 0;
}