【问题标题】:C++ change member type in derived classC ++更改派生类中的成员类型
【发布时间】:2011-09-24 15:57:00
【问题描述】:

我有一个类 Base1,它包含一个不同类 Base2 的对象数组。我想要一个派生类 Derived1,它继承 Base1 的所有内容,除了数组是 Derived2 类型(它是 Base2 的派生类)。例如,像这样:

class Base2{
        int a2;
};

class Derived2: public Base2{
        int b2;
};

class Base1{
        Base2* list;
};

class Derived1: public Base1{
        Derived2* list;
};

我的理解是,在上面的例子中,Derived1 的一个对象实际上会有两个数组:

list

Base1::list

这是我不想要的。

我们的想法是 Base1 的所有功能仍应适用于 Derived1 对象,因为 Derived2“是”Base2。这真的很脏,但我想我可以在 Derived1 构造函数中删除 [] Base1::list 数组。

有没有人看到这个问题的解决方案?这似乎是经常发生的事情,我无法相信一个简单的解决方案不存在。使用模板会起作用吗?我的想法是否定的,因为 Base1 和 Derived1 中的所有功能都需要知道它们分别处理的是 Base2 和 Derived2 对象。

【问题讨论】:

  • 你应该使用模板而不是继承,IMO
  • @onof:从问题来看,现在开始讨论模板还为时过早。
  • A Derived2Base2,但 Derived2数组 不是 Base2 的数组,如果 Derived1 尝试使用 @ 987654329@ 依赖于Base2* 指针运算的方法,你会遇到问题。 (顺便说一下,糟糕的名字。)
  • 如果这按您希望的方式工作,并且您有一个 Derived1 并在其上调用了一个 Base1 方法,那么从 Base1 的角度来看,将 anything 派生自 Base2 是完全有效的在数组中,即使数组本身只能存储指向 Derived2 的指针。
  • @Carl:问题是为什么Derived1 关心它是list 中的Derived2*s 而不是Base2*s?如果您使用继承正确list 可以是Base2* 类型并包含Derived2* 的实例,并且您需要从Derived2 获得的任何特殊行为都可以通过调用定义的虚拟成员函数来访问在Base2 中,随后在Derived2 中被覆盖。

标签: c++ inheritance overloading


【解决方案1】:

当有人将 Derived1 类向下转换为 Base1 时,您期望会发生什么?在破坏基类后使用list 时,它会崩溃。最好的办法是继续使用基类的list,并确保只有Derived2 类型的对象被放入列表中。如果列表的内容不能被外部修改,那将是可行的并且是安全的。

是的,我知道对此还有很多话要说,但让我们一步一步来。

【讨论】:

    【解决方案2】:

    在一般情况下,您尝试做的事情似乎很危险,但我假设您知道风险;)

    我可以提出两种解决方案:

    选项 1:

    您可以在protected 部分中隐藏实际指针并提供访问功能。

    class Base1 {
        protected:
        void *ptr
        public:
        Base2 *list() {return (Base2*)ptr;}
    };
    
    class Derived1 : public Base1 {
        public:
        Derived2 *list() {return (Derived2*)ptr;}
    };
    

    基本上,Base2::list 将被Derived2::list 隐藏。请注意,您不能将它们设为虚拟并从虚拟中受益。返回类型必须在编译时知道。

    选项 2:

    您可以使用模板化基类。

    template <typename T>
    class List {
        public:
        T *list
        //implement all functionality which is common, regardless of the type T
    };
    
    class Base1 : public List<Base2> {
        //specifics for Base2 type
    };
    
    class Derived1 : public List<Derived2> {
        //specifics for Derived2
    };
    

    请注意,在此构造中,Base1 和 Derived1 没有直接关系,而是有一个共同的祖先。

    【讨论】:

      【解决方案3】:

      我会从 Base1 中删除 Base2 的数组,并使用列表创建一个新类:

      class Base2{
              int a2;
      };
      
      class Derived2: public Base2{
              int b2;
      };
      
      class Base1{
      };
      
      class Base1WithList : public Base1{
              Base2* list;
      };
      
      class Derived1: public Base1{
              Derived2* list;
      };
      

      【讨论】:

        【解决方案4】:

        我认为没有任何简单的方法可以解决您的问题。

        我会使用以下方法之一 -

        选项 1 通过将其设为私有来隐藏 Base2* 列表(在 base1 类中),并将其保存为由派生类 (derived1) 继承。当然,在 base1 类中定义一个 getter 函数来访问列表。

        选项 2 只需将 base1 类中的列表类型更改为(指向) Derived2 的指针,并依赖于指向派生类的指针与指向其基类的指针类型兼容这一事实。

        选项 3 忘记继承并使用模板。您只需在实例化对象时指定类型(Base2* 或 Derived2*),生活将再次美好。

        【讨论】:

          【解决方案5】:

          @ildjarn 的question comment 给了我解决类似问题的方法:

          class Base {
              Base* children;
          };
          
          class Derived : public Base {
              int answer;
             public:
              void give_answer() {
                  this->answer == 42;
                  for(auto child : this->children) {
                      // at this point `give_answer` is not defined for items of `children`
                      child->give_answer();  // -> error: ‘class Base’ has no member named ‘give_answer’
                  }
              };
          };
          

          解决办法是在Base中引入一个虚函数:

          class Base {
              Base* children;
             public:
              virtual void give_answer();
          }
          

          virtual void give_answer() = 0; 也可以,使Base 抽象化。

          (这个例子有点做作,因为为什么还要有Base,但在我的用例中Derived实际上是Derived&lt;T&gt;,而Base是一个完整的树实现。)

          【讨论】:

            猜你喜欢
            • 2017-12-02
            • 1970-01-01
            • 1970-01-01
            • 2017-11-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-07-25
            • 1970-01-01
            相关资源
            最近更新 更多