你好!
我有一个游戏引擎的工作原型,现在我正在做一些重构。 我要求的是您对使用以下C ++编码模式的看法。
我已经实现了一些用于碰撞检测的简单算法,它们通过以下方式实现:
此处未显示 - 类构造函数是私有的,使用的算法类似于 Algorithm::HandleInnerCollision(...)
class Algorithm {
// Private routines
static bool is_inside(Point& p, Object& object) {
// (...)
}
public:
/**
* Handle collision where the moving object should be always
* located inside the static object
*
* @param MovingObject & mobject
* @param const StaticObject & sobject
* @return void
* @see
*/
static void HandleInnerCollision(MovingObject& mobject, const StaticObject& sobject) {
// (...)
}
所以,我的问题是 - 有人建议我以“C ++”的方式做 - 所有功能都包含在命名空间中,但不包含在类中。是否有一些保存私有的好方法,如果我按照建议将它们包装到命名空间中?
我想要的是一个简单的界面,能够将函数调用为Algorithm::HandleInnerCollision(...)
,同时不会使用is_inside(...)
如果你能为这种逻辑建议任何替代设计模式,我真的很感激......
答案 0 :(得分:2)
有几种惯用的方法可以做到这一点。第一种方法是,在有实现文件(cpp文件)的地方,只需在该文件中使用未命名的命名空间来获取全局函数或变量。未命名的命名空间实际上并不是未命名的,而是在每个翻译单元中都有一个您无法键入的唯一名称。如果你的函数是在头文件中内联,那么你不能这样做 - 通常的方法似乎是在你的特性命名空间中使用名为detail的命名空间。这不是真正的私密性,但开发人员很容易独自离开。
您应该注意的一件事 - 您的示例中的函数is_inside在注释中标记为私有,但实际上并不是私有的。默认情况下,struct成员是公共的 - 实际上这是结构和类之间的唯一区别,因为你不在它之前使用private,它是公共的。
答案 1 :(得分:2)
您可以在一个命名空间中显示所需的函数,然后在另一个命名空间中使用is_inside()
等函数,例如:
namespace othernamespaceHelperFunctions
{
...helper functions...
}
让你想要使用的命名空间是唯一使用辅助函数命名空间的东西。
答案 2 :(得分:1)
是的,您可以使用未命名的命名空间:
namespace
{
int private_variable;
}
int f()
{
return private_variable;
}
private_variable 只能在当前翻译单元内看到。
但一般来说,我认为这不是一个好主意。更好地使用类,OOP,组件。 :)越高越好。这是现代C ++方式。
答案 3 :(得分:1)
好吧,为了回答你的初始问题,要对一个函数进行“私有化”,你可以使用static,如果你希望它是该文件的本地文件,或者你可以将它放在私有头文件中,如果你想在整个过程中使用它你的代码。即,您的.cc文件中包含static bool is_inside(const Point& point, const Object& object);
或将声明放在algorithmsPrivate.hh
内。
然而,真的,你在这里编写类似C的代码。如果你想用C ++方式做,你可以在Object
类中添加一个方法:
class Object {
...
bool contains(const Point& point) const;
}
关于这一点的一个好处是它甚至可以让你使这个功能成为虚拟的。
virtual bool contains(const Point& point) const;
然后,当您实现每个Object
时,它可以拥有自己的contains函数实现。
答案 4 :(得分:1)
如果各种功能彼此有关,如果它不仅仅是帮助而且确实有一个共同因素,例如作用于同一个实体,那么就把它们放在一个类中。另一方面,如果函数作用于与其他实体相同的实体,但您也希望将其重用于可转换为第一个实体的其他实体,则将其从类外部提取出来:
bool same_size(const shape& a, const shape& b)
{
return a.bounding_x == b.bounding_x && a.bounding_y == b.bounding_y;
}
上述函数适用于可转换为shape
或来自namespace {
bool is_inside(Point& p, Object& object)
{
// ...
}
// ...
}
的任何两个对象。
将您不想与其他翻译单元(即辅助函数和帮助对象)共享的功能放在未命名的命名空间中。这是C静态函数的C ++等价物,它指示编译器将未命名的命名空间内的任何内容保存为此转换单元的私有。
namespace kotti {
void HandleInnerCollision(MovingObject& mobject,
const StaticObject& sobject)
{
// ...
}
// ...
}
将要与其他翻译单元共享的所有功能放在命名的命名空间中。这将指示编译器使用通用名称包装代码,因此名称不会与外部代码(库等)名称冲突。
{{1}}
答案 5 :(得分:0)
我认为你应该将它保持为静态类。它为您提供了您想要的公共/私人的好处,我认为没有任何缺点。我一直认为使用命名空间的方式与其他答案建议的方式一样。在我看来,名称空间用于对相关类和自由函数进行分组,以及用于防止名称冲突,而不是用于提供封装。