友谊没有继承 - 有哪些替代方案?

时间:2011-07-05 16:41:51

标签: c++ inheritance physics analysis friend

我已经写过/我正在编写一段物理分析代码,最初是为了我自己,现在希望由一小群物理学家使用和扩展。我们都不是C ++大师。我已经整合了一个小框架,将“物理事件”数据抽象为由一系列工具操作的对象,这些工具可以根据分析要求轻松交换进出。

这创造了代码的两半:“物理分析”代码,它操纵事件对象并通过基础“工具”的衍生产生我们的结果;以及附加输入文件的“结构”代码,将作业拆分为并行运行,根据某些脚本将工具链接到链中等。

问题在于:对于其他人来说,要使用代码,每个用户都应该能够遵循以任何方式修改事件数据的每一步。因此,(许多)额外的困难结构代码线可能是令人生畏的,除非它明显且明显地是物理学的外围。更糟糕的是,在太多细节上查看它可能会给人们提供想法 - 我宁愿他们没有很好的理由也不编辑结构代码 - 最重要的是他们不得引入任何影响物理的东西。

我希望能够:

  • A)以明显的方式证明 结构代码不编辑 事件数据以任何方式
  • B)强制执行此用户一次 开始自己扩展代码 (我们都不是 专家,物理学总是来 第一 - 翻译:没有 狂奔是公平的游戏,令人讨厌 劈)

在我的理想场景中,事件数据将是私有的,派生的物理工具继承了Tool基类的访问权限。当然,实际上这是不允许的。我听说有充分的理由,但这不是问题。

不幸的是,在这种情况下,从基础(它是朋友)调用getter / setter的方法会产生比它解决的问题更多的问题 - 代码应该干净,易于遵循,并且与物理连接尽可能在工具本身的实现中(用户不需要是C ++的专家或程序的内部工作来创建工具)。

鉴于我有一个值得信赖的基类,任何衍生品都会受到密切关注,是否还有其他环形交叉口但经过充分测试的方式只允许访问这些衍生品?或者是否有任何方式拒绝访问某些其他基地的衍生物?


为澄清情况,我有类似

的内容
class Event
{
    // The event data (particle collections etc)
};

class Tool
{
    public:
        virtual bool apply(Event* ev) = 0;
};

class ExampleTool : public Tool
{
    public:
        bool apply(Event* ev)
        {
            // do something like loop over the electron collection
            // and throw away those will low energy
        }
};

由于上述两个原因(A和B),理想的做法是将对Event内容的访问权限仅限于这些工具。

感谢大家提出的解决方案。我认为,正如我所怀疑的那样,我所希望的完美解决方案是不可能的。 dribeas的解决方案在任何其他设置中都是完美的,但它恰好在apply()函数中,代码需要尽可能清晰和简洁,因为我们基本上会花一整天时间编写/编辑apply()函数,并且还会需要了解每个人写的每一行。它与可读性和努力能力无关。我喜欢“无用”的预处理器解决方案。它并没有真正强制执行分离,但有人需要真正恶意破坏它。对于那些建议使用图书馆的人,我认为这肯定是一个很好的第一步,但并没有真正解决两个主要问题(因为我仍然需要提供资源)。

3 个答案:

答案 0 :(得分:2)

C ++中有三种访问限定符:publicprotectedprivate。带有派生物理工具的句子继承工具基类的访问权限似乎表示您希望protected访问,但不清楚实际数据是private位于Tool(因此protected就足够了)或当前private位于与Tool成为朋友的班级中。

在第一种情况下,只需制作数据protected

class Tool {
protected:
   type data;
};

在第二种情况下,您可以尝试对语言进行讨厌的技巧,例如,在工具级别提供访问器:

class Data {
   type this_is_private;
   friend class Tool;
};
class Tool {
protected:
   static type& gain_acces_to_data( Data& d ) { 
       return d.this_is_private;
   }
};
class OneTool : public Tool {
public:
   void foo( Data& d ) {
      operate_on( gain_access_to_data(d) );      
   }
};

但我会完全避免它。有一点,访问说明符停止有意义。它们是避免错误的工具,而不是警察你的同事,事实是,只要你希望他们编写需要访问这些数据的代码(Tool扩展名),你可能会忘记绝对保护:你不能。

想要访问数据的用户也可以使用新创建的后门来执行此操作:

struct Evil : Tool {
   static type& break_rule( Data & d ) {
      return gain_access_to_data( d );
   }
};

现在每个人都可以使用Evil作为Data的大门。我建议您阅读C++FAQ-lite以获得有关C ++的更多信息。

答案 1 :(得分:2)

将代码作为库提供,以供想要创建工具的人使用。这很好地封装了你想保持完整的东西。如果每个人都可以访问源并且热衷于对任何事情进行更改,那么就不可能防止黑客入侵。

答案 2 :(得分:0)

还有C风格的方法,限制可见性而不是访问权限。它更符合惯例和(在某种程度上)您的构建系统而不是语言 - 尽管您可以使用一种包含防护来防止工具实现细节“意外”泄漏到结构代码中。

-- ToolInterface.hpp --
class Event; // just forward declare it

class ToolStructuralInterface
{
    // only what the structural code needs to invoke tools
    virtual void invoke(std::list<Event*> &) = 0;
};

-- ToolImplementation.hpp --
class Event
{
    // only the tool code sees this header
};
// if you really want to prevent accidental inclusion in the structural code
#define TOOL_PRIVATE_VISIBILITY

-- StructuralImplementation.hpp --
...
#ifdef TOOL_PRIVATE_VISIBILITY
#error "someone leaked tool implementation details into the structural code"
#endif
...

请注意,这种分区有助于将工具和结构代码放在单独的库中 - 您甚至可以将结构代码的访问权限分别限制为工具代码,只需共享标头和已编译的库。 / p>