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

发布于 2024-09-24 05:21:20 字数 2240 浏览 7 评论 0原文

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

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

因此,我创建了一个派生的 EnhanceItr 类来执行此操作。 我的问题是我无法找到一种方法来处理数百个这样的代码:

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

anArray 时使用 EhancedItrgetData() 函数code> 是一个 EnhancedArray

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

#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;
}

当我希望第二个调用返回 0 时,上面对 vfunc() 的两次调用都返回 1。

main() 中,我知道如果我更改 ItrBase 类型转换为 ItrBase &'s,我确实得到了所需的返回类型,但随后我在数百个区域修改了我的“现有”代码,并且迭代器的析构函数不是叫。

还有其他我没有看到的策略吗?

谢谢。

I have an existing application in C++ with a custom ArrayBase class that manages storage and access to a contiguously allocated region of memory. I have a separate ItrBase class that is used to access data in that ArrayBase. ArrayBase has a createItr() function that currently returns an ItrBase object.

I need to extend ArrayBase to use multiple memory allocations instead of one contiguous one. I have created an EnhancedArray class to do that. For this EnhancedArray to be compatible with the existing application, it's createItr() function must return something that works with the new multiple memory allocations.

So, I have created a derived EnhanceItr class to do this.
My problem is I can't figure out a way for hundreds of code occurrences like this:

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

to use the EhancedItr's getData() function when anArray is an EnhancedArray.

Here is a simple application illustrating my basic arrangement.

#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;
}

Both calls to vfunc() above return 1, when I want the second call to return 0.

In main(), I know that if I change the ItrBase types to ItrBase &'s, I do get the desired return types, but then I am modifying my 'existing' code in hundreds of areas, and the destructors for the Iterators are not called.

Is there another strategy that I am not seeing?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

鸢与 2024-10-01 05:21:20

当然,如果您被允许重写 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); };
};

Sure, if you're allowed to rewrite ItrBase, then you can use delegation to pass all function calls through to an implementation class, which you hold by pointer or reference so that polymorphism is in effect. This would look a lot like pimpl. And the callers would not have to be written at all, only recompiled.

EDIT: code for those not familiar with 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); };
};
夜光 2024-10-01 05:21:20

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

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

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

You're running into a problem called slicing: createItr returns a reference, and then you're copying that into an ItrBase by-value. It's as if you did something like this:

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

You're also leaking memory: createItr returns a newly allocated object, but you're never deleting it. This is very bad, especially since you'd expect array iterators to be used frequently.

眉黛浅 2024-10-01 05:21:20

您可以做的完全不同的事情是使用,

BOOST_AUTO(iterator, array);

并让编译器计算出返回类型。

BOOST_AUTO

completely different thing you can do is use,

BOOST_AUTO(iterator, array);

and let compiler figure out return type.

BOOST_AUTO

鹿! 2024-10-01 05:21:20

由于没有及时更新标准库,我无法使用 Ben Voigt 建议的 unique_ptr 实现。 (版本> = 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;
}

Not being up-to-date with the Standard Library, I could not use the unique_ptr<> implementation suggested by Ben Voigt. (version >=4.3) I believe I have taken his concept and implemented it with basic pointers instead. Noting, however, that this implementation is not exception-safe. ItrImpl objects could be left undeleted.

Here's my code. Too bad createItr() has to return a ItrBase object rather than a pointer, otherwise I think I could have gotten auto_ptr<> to work. Output during program execution shows that ~ItrBase() is called only once for each instance, but I am suprised it is not called also during the object return from createItr(). Return value optimization?

#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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文