【问题标题】:Overriding function called by base class?基类调用的重写函数?
【发布时间】:2013-01-12 04:09:44
【问题描述】:

我有一个设计为通用的类,可以在任何地方使用,看起来有点像这样:

class FixedByteStream {
public:
  FixedByteStream(const char* source)
  {
    size = strlen(source);
    copy(source);
  }

  /* Many more constructors here */

protected:
  void copy(const char* source)
  {
    address = allocate();
    //...
  }

  /* Plus other functions that call allocate() */

  char* FixedByteStream::allocate()
  {
    return (char*)malloc(size);
  }
}

然后我扩展了这个类,以便它可以使用特定于项目的内存池。

class PooledByteStream : public FixedByteStream {
public:
  PooledByteStream::PooledByteStream() : FixedByteStream() {}

protected:
  char* PooledByteStream::allocate()
  {
    return (char*)PooledByteStream::pool.allocate(size);
  }
}

PooledByteStream 应该与 FixedByteStream相同,具有所有相同的函数和构造函数,除了调用 allocate() 时,它应该从内存池中检索指针。

然而,PooledByteStream::allocate() 从未 被调用过。不是来自继承的构造函数,也不是来自其他继承的函数(调用继承的 copy())。从基类继承的任何东西都完全没有注意到 allocate() 现在应该做一些完全不同的事情。

问题是,我该如何解决这个问题?如何使继承的函数调用重写的函数,而不是基类的函数?从基类复制粘贴所有必要的函数会抹杀继承点,所以我假设这不是这里的答案。

注意:我不是在寻找关于内存管理的建议,或其他方法来达到相同的最终结果。这只是一个例子!

【问题讨论】:

  • 你把它虚拟化了吗?
  • 你能发布 FixedByteStream 默认构造函数吗?

标签: c++ inheritance constructor


【解决方案1】:

您需要将allocate() 声明为虚拟才能覆盖它。但是,基类构造函数不能调用派生类的重写,因为派生类尚未构造,基类析构函数不能调用派生类的重写,因为派生类已经被析构。

如果必须在基类构造函数中调用allocate(),可以使用模板绕过限制,例如:

template<typename Derived>
class FixedByteStreamBase
{
public:
  FixedByteStreamBase(const char* source)
  {
    size = strlen(source);
    copy(source);
  }

  /* Many more constructors here */

protected:
  void copy(const char* source)
  {
    address = Derived::allocate();
    //...
  }

  /* Plus other functions that call allocate() */
};

class FixedByteStream : public FixedByteStreamBase<FixedByteStream>
{
public:
    static char* allocate()
    {
        return (char*)malloc(size);
    }
};

class PooledByteStream : public FixedByteStreamBase<PooledByteStream>
{
public:
    static char* allocate()
    {
        return (char*)pool.malloc(size);
    }
};

或者:

struct MallocAllocator
{
    static char* allocate()
    {
        return (char*)malloc(size);
    }
};

struct PoolAllocator
{
    static char* allocate()
    {
        return (char*)pool.allocate(size);
    }
};

template<typename Allocator>
class FixedByteStreamBase {
public:
  FixedByteStreamBase(const char* source)
  {
    size = strlen(source);
    copy(source);
  }

  /* Many more constructors here */

protected:
  void copy(const char* source)
  {
    address = Allocator::allocate();
    //...
  }

  /* Plus other functions that call allocate() */
};

typedef FixedByteStreamBase<MallocAllocator> FixedByteStream;
typedef FixedByteStreamBase<PoolAllocator> PooledByteStream;

【讨论】:

  • 奇怪的是,将allocate() 声明为虚拟确实使其工作,并且调试(以及仅内存分析)显示从基本构造函数调用的派生版本。基本 de 结构体仍然调用基本版本的deallocate()(正如它在锡上所说的那样),但它只需要一个小变通方法来防止它尝试释放池内存。
  • 除了编译器错误之外,基类构造函数/析构函数不可能调用派生类中的覆盖方法。在基类构造函数/析构函数运行时,派生类的 vtable 根本不存在于 this 指针中。
  • 我的意思是:“当基类构造函数/析构函数运行时,派生类的 vtable 根本无法从 this 指针访问。”
猜你喜欢
  • 2011-05-03
  • 2011-06-17
  • 2023-01-04
  • 1970-01-01
  • 1970-01-01
  • 2021-05-09
  • 2017-02-04
  • 2013-08-02
相关资源
最近更新 更多