【问题标题】:C++ design pattern: Possible to have inherited method private to derived class?C++ 设计模式:可能有继承的方法私有到派生类?
【发布时间】:2023-03-17 06:14:03
【问题描述】:

以下设置/设计模式在 C++ 中是否可行?

  • Leader 类
  • 工人阶级
    • 有方法 M()
  • 一个 MyWorker 类(继承 Worker)

Leader类有很多Worker,需要调用Worker类的M()方法。但是,我不希望 Worker 的任何实现(即 MyWorker)能够访问方法 M()。在这种情况下,public、private 和 protected 似乎都不起作用。

这种设置可行吗?或者我应该如何设计?

谢谢

编辑:(添加示例)

假设 M() 是 GiveMoney(),Leader = Parent,Worker = Child。我只希望父母能够给孩子钱(孩子不能给自己钱)。

【问题讨论】:

  • 您希望一个类不能访问它自己的方法,但希望该方法可以从另一个类调用?我认为这在任何语言中都是不可能的。
  • 邮政编码,如果将 M() 定义为私有;并且通过 public 进行扩展应该会导致 MyWorker 无法访问私有方法。只要 Worker(M() 的原始所有者)是唯一调用 M() 的东西,M() 是私有的这一事实应该可以正常工作,因为通常一个实例可以对其他实例上的私有方法/成员进行操作同班。
  • 如果 M() 被定义为 private 并且 LeaderWorker 的朋友,那么一切都应该如你所愿 - 如果我理解正确的话。跨度>

标签: c++ design-patterns inheritance


【解决方案1】:

你可以:

  1. M() 设为Worker 中的私有函数,并将Leader 声明为Worker 的朋友。
  2. M() 的逻辑移出Worker 并移入Leader。就个人而言,这是我会采取的方法,因为无论M() 做什么,你都不希望任何其他Worker 去做。

【讨论】:

    【解决方案2】:

    像这样:

    #include <iostream>
    
    class Leader
    {
      private:
        virtual char M() = 0;
      public:
        void foo() { std::cout << M(); }
    };
    
    class Worker : public Leader
    {
      private:
        virtual char M() { return 'm'; }
    };
    

    然后

    int main()
    {
      Worker w;
      w.foo();
    }
    

    打印m

    class MyWorker : public Worker
    {
      void foo2() { std::cout << M(); }
    };
    

    导致编译错误,报错

    ‘virtual char Worker::M()’是私有的。

    【讨论】:

    • 不想让Worker继承Leader怎么办?举个例子,假设方法是 AddFood() 并且我不希望工人能够养活自己。
    • 那么你必须让Worker成为Leader的朋友,或者你必须重写Leader,使其不必调用Worker::M(例如,通过移动功能这需要调用 Worker 类(但这可能不适合您的特定情况)。
    【解决方案3】:

    拥有M 私有,并将Leader 声明为Worker 的朋友。你仍然可以在Worker的派生类中实现M

    class Leader;
    
    class Worker
    {
        virtual void M() = 0;
        friend class Leader;
    };
    
    class Leader
    {
        Worker* w;
    
    public:
        void doSomething() { w->M(); }
    };
    
    class MyWorker : public Worker
    {
        void M() { ... } // No problem. Even if `M` is private in the base class, it
                         // can still be overridden, but not accessed.
    };
    

    【讨论】:

      【解决方案4】:

      为什么要这样做?你到底想达到什么目的?了解您的最终目标将帮助我们帮助您找到您正在寻找的答案。

      如果您想完全隐藏一些实现细节,最好的办法是为工作人员的公共方面创建一个单独的基类,让您的私人工作人员按组合包含公共位。

      编辑在我看来,你给自己的生活带来了不必要的困难。除非其他人可以控制童工的实施,否则为什么不直接避免从童工那里打电话给钱呢?

      这样的事情可能适用于您的示例:

      class Parent // Leader
      {
      private:
          Child* m_pChildren;
      };
      
      class Child : public ChildSelf
      {
      public:
          char GiveMoney() { return 'm'; }
      };
      
      class ChildSelf
      {
          Run();
          Jump();
          ClimbTrees();
      };
      
      class MyChild : public ChildSelf
      {
          void RunFaster() { Run(); Run(); }
      };
      

      您的子工作者实现只能访问 ChildSelf,它可以为您提供所需的安全级别.. ?

      【讨论】:

        【解决方案5】:

        听起来您应该研究访问者设计模式:http://en.wikipedia.org/wiki/Visitor_pattern

        这不是完全相同的方法,但我相信如果你在Leader 类上定义一个Visit(Worker) 方法,在Worker 类上定义一个Accept(Leader) 方法,然后调用private M(),你可以获得您正在寻找的功能。

        看到我的帖子被否决了,我决定如果我提供一些额外的信息可能会有所帮助:

        class Leader;
        
        class Worker
        {
        virtual void M() = 0;
        public:
            void Accept( const Leader & w)
                {
                    M();
                }
        };
        
        class Leader
        {
        public:
        void Visit ( Worker & w) const
            {
            w.Accept(*this);
            }
        };
        
        class MyWorker : public Worker
        {
        virtual void M()
            {
            std::cout << "M()" << std::endl;
            }
        };
        
        
        int main(int argc, char **argv)
        {
        Leader l;
        MyWorker myW;
        myW.Accept(l)
        return 0;
        }
        

        调用M() 的唯一方法是使用LeaderWorker 是一个抽象类,甚至不能被实例化,尽管您可以为M() 提供默认行为如果你愿意。

        【讨论】:

          猜你喜欢
          • 2017-04-14
          • 1970-01-01
          • 2015-01-20
          • 2021-09-15
          • 2021-12-20
          • 1970-01-01
          • 2016-10-08
          • 2016-03-04
          • 2011-01-09
          相关资源
          最近更新 更多