我怎样才能避免这种丑陋的嵌套 class C++ 代码

How can I avoid this ugly nested class c++ code

我用 C++ 和 SDL 编写游戏。我用 C 编写游戏已经一年多了,现在我已经用 C++ 编写了 7 个月。我试图避免几乎所有全局变量并转向所有权系统,其中每个对象都由其他对象拥有。这样我就可以管理 class 拥有 shared_ptr 成员的人的生活,而且几乎从不担心释放指针。

例如,我的游戏是 class 及其子系统。

class Game
{
public:
   Game();
   ~Game();
   void runFrame();

   std::shared_ptr<Display> display;
   std::shared_ptr<Audio> audio;
   std::shared_ptr<Save> save;
};

但我 运行 喜欢看起来凌乱的嵌套 classes,就像我下面的音频 class。

class Audio
{
public:
   Audio(Game& parent);
   ~Audio();

   struct MusicFiles;
   struct SfxFiles;
   std::shared_ptr<MusicFiles> musicFiles;
   std::shared_ptr<SfxFiles> sfxFiles;

private:
   class Music
   {
   public:
      class File
      {
      public:
         File(Music& parent, std::string fileAddr);
         ~File();
         void play();
         void fadeIn();
         void stop();
      private:
         Music& _parent;
         std::string addr;
         Mix_Music* chunk;
      };

      Music(Audio& parent);
      ~Music();
      void setVolume();

   private:
      Audio& _parent;
      bool _enabled;
      int _volume;
   };

   class Sfx
   {
   public:
      class File
      {
      public:
         File(Sfx& parent, std::string fileAddr);
         ~File();
         void play();
         void stop();
      private:
         Sfx& _parent;
         std::string addr;
         Mix_Chunk* chunk;
         int channel;
      };

      Sfx(Audio& parent);
      ~Sfx();
      void setVolume();

   private:
      Audio& _parent;
      bool _enabled;
      int _volume;
   };

   Game& _parent;
   Music _music;
   Sfx _sfx;
};

我嵌套了 classes,因为我不喜欢在每个函数名称中写 "Music" 或 "Sfx",例如 setMusicVolume()、setSfxVolume()、setMusicHook()、setSfxHook (),等等等等 我可以拉出嵌套的 classes 但音乐和 Sfx 只需要存在于音频 class 中。我宁愿重新组织一切,有一个更好的设计。

您有什么更好的设计建议吗?

将各种 class 组织成一个 namespace 以将它们分组,而不是单个 class。这东西一旦长大,就很难维护了。您想使用 classes 来 封装 功能,并为 'outside world' 提供一个简单而全面的界面。通常,每个 class 将获得自己的头文件(.h.hpp)和编译单元(.cpp)。

接受 many good reasons 用于使用 getter 和 setter 函数 - 它们是良好封装的基础。如果确实需要,您始终可以在嵌套的 class 中使用 friend class Audio 以使 privateprotected 成员对 Audio 可见,但不是对所有人可见您项目中的其他 class 可能(在将来的某个时间,也许)包括这些 class。

你说你不喜欢写 audio.setMusicVolume(0.8f) 而不是 audio.music.setMusicVolume(0.8f)。有些人可能会说 audio.getMusic().setVolume(0.8f) 会是一个很好的折衷方案,但如果需要,Demeter disagrees. By using wrapper functions like setMusicVolume, every other class only needs to know about and communicate with Audio while Music is strictly internal and only known by Audio itself. If you use function chaining, you lose this advantage and expose Music and Sfx to the world - which is not necessarily a bad thing. If you want to stick to your syntax, my suggestion would be to keep the public interfaces very small and use friend 可以向 Audio 公开更多功能。

仅供参考,除了使用命名空间之外,嵌套类型还可以像成员函数一样通过使用它们的限定名称来放置在行外。所以你可以这样做:

class Audio
{
public:
   Audio(Game& parent);
   ~Audio();

   struct MusicFiles;
   struct SfxFiles;
   std::shared_ptr<MusicFiles> musicFiles;
   std::shared_ptr<SfxFiles> sfxFiles;

private:
   class Music;
};

在另一个文件中

#include "Audio.h"

class Audio::Music
{
public:
  class File;

  Music(Audio& parent);
  ~Music();
  void setVolume();

private:
  Audio& _parent;
  bool _enabled;
  int _volume;
};