公开对象的子方法而不重复

时间:2012-01-27 19:11:58

标签: c++ oop

我有一个类Level的对象,它有几个用于管理其状态的子系统(子对象)(例如EntityManagerInputManagerPhysics)。我想在Level的外部接口中公开这些子系统的一些方法。

这是一个解决方案:

uint32_t Level::CreateEntity()
{
    return entityManager.CreateEntity();
}

Entity& Level::GetEntity(uint32_t entityId)
{
    return entityManager.GetEntity(entityId);
}

uint16_t Level::CreateInputState()
{
    return inputManager.CreateInputState();
}

void Level::AttachInputState(uint32_t entityId, uint16_t inputStateId)
{
    inputManager.AttachInputState(entityId, inputStateId);
}

InputState& Level::GetInputState(uint16_t inputStateId)
{
    return inputManager.GetInputState(inputStateId);
}

此解决方案要求我复制Level类中的方法声明,并编写将控件重定向到子系统的单行调用。在我过去曾经做过的项目中,管理起来很麻烦。

另一种解决方案是在公共接口中公开子系统。最好这可以避免,因为对于Level以外的对象来说,调用转发到哪个子系统并不重要。

是否有设计可以更优雅地处理此问题?

3 个答案:

答案 0 :(得分:1)

根据OP的要求,我将发布我在评论中建议的解决方案。 我很确定,在新的C ++标准中有一个更好的模板,但无论如何我会发布丑陋且不应该使用的预处理器解决方案!

#define FUNCTION_DECLARATION(RETURNTYPE, FUNCTIONNAME, ...) \
     RETURNTYPE FUNCTIONNAME(__VA_ARGS__)

这将在类声明中用作:

class Level {
    FUNCTION_DECLARATION(uint32_t, CreateEntity);
    FUNCTION_DECLARATION(Entity&, GetEntity, uint32_t);
};

定义如下:

#define FUNCTION_DEFINITION(RETURNTYPE, PROPERTY, FUNCTIONNAME, ...) \
    RETURNTYPE Level::FUNCTIONNAME(__VA_ARGS__) \
    { \
        return PROPERTY.FUNCTIONNAME(__VA_ARGS__); \
    } \

现在使用这个非常难看的用法:

FUNCTION_DEFINITION(Entity&, entityManager, GetEntity, uint32_t(entityId))

我不能保证这对任何类型都有效,我还没有测试过大部分代码。正如您所看到的,输入的“hack”仅适用于普通类型而不适用于引用或指针。在类上它将触发复制构造函数!

当然这可以通过将VA_ARGS替换为函数的每个参数的类型和变量名的变量来改进,但这又是非常乏味的,并且必须为每个应该为的每个参数编写一个模板。用过的。结果这将产生与以前一样多的代码。

所以让我再说一遍:坚持使用模板远远比这更好! 只是我不知道如何与他们一起做。所以,如果有人知道如何使用模板,而不是抨击我 ** 代码,请写下这个美丽的解决方案,每个人都渴望。

答案 1 :(得分:1)

聚合功能的另一种方法是通过私有继承。然后,您可以使用using指令将一些继承的私有方法转换为公共方法。例如:

#include <iostream>

class feature_A
{
public:
  void func_A1() { std::cout << "A1" << std::endl; }
  void func_A2() { std::cout << "A2" << std::endl; }
};

class feature_B
{
public:
  void func_B1() { std::cout << "B1" << std::endl; }
  void func_B2() { std::cout << "B2" << std::endl; }
};

class compound : private feature_A, private feature_B
{
public:
  // Provide these functions as-is.
  using feature_A::func_A1;
  using feature_B::func_B1;

  // Combine these two functions.
  void func_C2() { func_A2(); func_B2(); }
};

int main()
{
  compound c;
  c.func_A1();
  c.func_B1();
  c.func_C2();
  // c.func_A2();   // error: ‘void feature_A::func_A2()’ is inaccessible
}

这些using声明的一个限制是它们具有名称。如果您有多个相同功能的重载,则不能只选择一个要公开的重载。类似地,对于模板方法:您不能使用using仅选择一个专门化。

答案 2 :(得分:0)

我认识的唯一想法是让界面更优雅的是让另一个对象包含private EntityManagerPhysics等等,并让它{{ 1)暴露函数,这些函数调用您希望客户端能够在底层对象上调用的每个函数。使public在公共接口中具有这些代理对象的实例,并可选择使这些代理不可复制,不可移动等。

这不会减少你的工作量(实际上会增加它),但它会使界面更有条理,更容易使用。

示例:

Level

然后你可以像

一样使用它
class Physics {
public:
    T gravity() { ... } // we want them to be able to call this

    T2 nope() { ... }   // but not this
};

class LevelPhysics {
public:
    T gravity() { return phys.gravity(); }

private:
    LevelPhysics(Physics& phys) : phys(phys) { }

    Physics& phys;

    friend class Level;
};

class Level {
public:
    LevelPhysics GetPhysics() { return LevelPhysics(phys); }

private:
    Physics phys;
};

不幸的是,没有语言功能可以“为你制作这些”。你不能自己做一些编码。

或者,如果您知道需要访问const LevelPhysics& phys = lvl.GetPhysics(); phys.gravity(); // but you can't use Physics::nope 的秘密成员的所有类,您可以这样做:

Physics

然后

class Physics {
public:
    T gravity() { ... }

private:
    T2 nope() { ... }

    friend class Level;
};

class Level {
public:
    Physics physics;
};