0

我正在编写一个 C++ 框架,以便我可以重写一些软件以在多个平台上工作。我的问题与一些使用 Windows 句柄的包装类的实现有关。考虑以下代码...

class Font
{
public:
  Font(const LOGFONT& lf)
  {
    m_hFont = ::CreateFontIndirect(lf);
  }

  ~Font()
  {
     ::DeleteObject(m_hFont);
  }

private:
  HFONT m_hFont;
}

然后我有一个 Display 类,我可以在其中调用以下内容......

LOGFONT lf;
// initialise lf

Display d;
d.SetFont(Font(lf));
d.DrawText(0,0,"Some Text");

问题当然是 d.SetFont 会导致 m_hFont 被 Font 类析构函数删除。我很欣赏我可以在堆上创建字体并让图形类负责字体的整体“生命周期”。我想这确实是一个设计问题。是不是更好...

  1. 为包装 Windows 句柄的类实现引用计数。
  2. 在堆上创建包装类。
  3. 还有什么方法?

我注意到 MFC 在其包装器中有一个明确的 DeleteObject ,但这当然不会导致自动资源取消分配。

任何帮助/建议表示赞赏。

谢谢

编辑:我认为这更像是一个复制构造函数问题。即我的 Font 类创建了一个 Windows FONT 句柄,但由于我将 Font 对象按值传递给显示而被破坏。

4

3 回答 3

1

你至少有三个选择:

  1. 注意“三法则”:如果一个类有一个非平凡的析构函数,那么它可能还应该实现一个复制构造函数和一个复制赋值运算符。在这种情况下,他们应该确保每个副本都有自己的m_hFont.

  2. 使用引用计数。

  3. 更改Display::SetFont为接受指向 aFont或 const 引用的指针。这样,您仍然可以创建Font“在堆栈上”,并且如果您只传递一个指针或对它的引用,则不会制作任何副本。

编辑

  1. Display::SetFont如果您直接接受 a ,您可能可以完全避免该问题LOGFONT。这样,Display类本身将管理字体(例如删除旧字体结构并创建新字体)。如果您打算Font仅在上面的上下文中使用对象(带有 a Display)并且字体更改很少,则此选项最有效。

  2. 使Font该类也将其LOGFONT作为成员并仅按需生成 HFONT。复制时,LOGFONT将被复制并被HFONT赋予无效值。如果 newFont::GetFont被调用(比如由Display),那么HFONT将被创建。在 Font 析构函数中,如果HFONT不是无效值,则将其删除。CreateFontIndirect如果不是所有副本都将用于调用,这将避免一些不必要的调用GetFont

于 2013-03-29T19:03:03.110 回答
0

这就是 Windows 的本质。当您以调用 CreateFontIndirect 之类的方式使用资源时,您必须在完成后调用 DeleteObject 或某种方法来释放资源。究竟是什么问题?您的程序没有按预期运行吗?除非 lf 在您使用它之前超出范围,否则应该没问题。

于 2013-03-29T18:38:21.993 回答
0

根据答案的建议和一些进一步的想法,我采用了以下方法。我认为 Display 类应该管理字体的生命周期。库用户将为显示类提供字体设置。基本代码如下...

struct Typeface
{
   bool Bold;
   int Width;
   int Height;    
};

class Font
{
public:
  Font();
  ~Font();  // calls DeleteObject(m_hFont)

  HFONT Handle() const { return m_hFont; }

  // Create will destroy the current font handle and create a new one
  void Create(const Typeface & tc);

private:
  HFONT m_hFont;
};

class Display
{
public:
  // select font modifies the display's current font
  void SelectFont(const Typeface& tf);

  // Draw a string using the display's selected font
  void DrawString(int x, int y, const String& text);

  // Draw a string using the supplied font
  void DrawString(int x, int y, const String& text, const Font& font);

private:
  Font m_hSelectedFont;  // Font handle automatically destroyed
};
于 2013-03-30T20:53:06.547 回答