【问题标题】:Friendship not inherited - what are the alternatives?没有继承的友谊 - 有什么选择?
【发布时间】:2011-09-28 23:36:43
【问题描述】:

我已经编写/正在编写一段物理分析代码,最初是为我自己编写的,现在有望被一小部分物理学家使用和扩展。我们都不是 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() 函数,并且还将需要理解其他人写的每一行。与其说是能力,不如说是可读性和努力。我确实喜欢“无用”的预处理器解决方案。它并没有真正强制分离,但需要有人真正恶意才能打破它。对于那些建议图书馆的人,我认为这肯定是一个很好的第一步,但并没有真正解决两个主要问题(因为我仍然需要提供源代码)。

【问题讨论】:

  • 如果需要使用或查看源代码的人都不是 C++ 专家,那么不要使用 C++。对于那些不精通 C++ 并且不太可能成为专家的人来说,C++ 是一种令人讨厌的语言,尤其是在使用繁重的 OO 技术时。
  • 这听起来很熟悉......谁或什么拥有事件数据?这些用户工具是应该更改事件数据,还是使用它来生成新的事件数据?
  • @DarenW,我强烈怀疑 OP 在这里别无选择......
  • 有没有办法把它编译成一个库?并且没有给他们来源?
  • 您似乎有几个相互矛盾的目标。如果“工具”可以修改事件,“结构代码”可以与“工具”结合,那么“结构代码”可以修改事件,是吗?

标签: c++ inheritance physics analysis friend


【解决方案1】:

C++ 中有三个访问限定符:publicprotectedprivate。这句话with the derived physical tools inherit access from the Tool base class似乎表明你想要protected访问,但不清楚private的实际数据是否在@987654327中@(因此 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) 用于描述程序问题,用代码示例,即使听起来很明显;-)
  • 感谢您的建议。 Evil 的情况会很好 - 我在 Tool 基类中内置了跟踪和日志记录,所有工具及其设置与配置脚本一起保存到程序输出中。如果记录的工具与脚本不匹配,那么很明显有人在作恶——如果他们确实与脚本匹配,那么它就会按照你的要求去做。但是感谢您的警告。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    还有 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
    ...
    

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

    【讨论】:

      猜你喜欢
      • 2011-06-16
      • 2016-05-04
      • 2013-10-10
      • 1970-01-01
      • 2011-11-19
      • 1970-01-01
      • 2010-10-10
      • 2019-08-19
      • 2016-06-16
      相关资源
      最近更新 更多