继承时避免覆盖成员

时间:2012-09-12 11:38:51

标签: c++ inheritance override

我需要使用C ++。 C ++ 11会很有趣,但我更喜欢没有。我有以下类结构。

class Wheel { /*...*/ };
class MtbWheel : public Wheel { /*...*/ };

class Bike { Wheel front_wheel; };
class Mountainbike : public Bike { MtbWheel front_wheel; };

现在,这完全有效:Mountainbike覆盖了front_wheel,因此可以使用MtbWheel。从技术上来说,我并不高兴。

  • 我不希望覆盖front_wheel,或至少限制继承类Wheel的类覆盖。
  • 我不想覆盖front_wheel,而只想“添加”属性。
编辑:是否有没有虚函数的解决方案,而是使用模板?

5 个答案:

答案 0 :(得分:4)

front_wheel班级中的Mountainbike成员 覆盖 front_wheel隐藏Mountainbike类实际上有两个front_wheel成员,但Bike类中的成员被Mountainbike中声明的成员隐藏。这意味着如果Bike访问front_wheel,它将访问类型为Wheel的对象,而当Mountainbike访问front_wheel时,它将访问类型为{的对象{1}} - 但这两个轮对象彼此不知道!

更好的OO设计是MtbWheel例如front_wheel中的指针(甚至更好的智能指针),并在Bike的构造函数中初始化它,以保存从Mountainbike派生的类的对象,该类最适合{{1} }}。这样,当访问front_wheel时,当然会有一种方式或其他虚拟功能发挥作用。

另一种解决方案,根据Steve Jessop在下面的评论中的建议,使用模板而不是使用多态,将是:

Wheel

这样,在front_wheel上操作时不会涉及虚函数。但是,有一些方面需要考虑这样的解决方案:

  • 对于每个使用Bike with的不同WheelType,将创建单独的代码;如果你有许多不同的类型,这可能会导致代码膨胀。
  • 如果您有多个派生自Mountainbike且具有不同WheelType参数的类,则具有相同的基类(请参阅Steve Jessop的评论和第1点),因此也不能多态访​​问。
  • 您无法强制将{em>显式接口作为模板参数传递给Bike class Wheel { /*...*/ }; class MtbWheel : public Wheel { /*...*/ }; template <typename WheelType> class Bike { WheelType front_wheel; }; class Mountainbike : public Bike<MtbWheel> { /* ... */ }; ;只有隐式接口由Bike中使用的方法和成员定义。那应该没问题,因为编译器仍然可以验证隐式接口。

答案 1 :(得分:1)

你没有压倒什么。派生类中仍有Wheel front_wheel;。您可以通过m.Bike::front_wheel或类似内容访问它。如果您希望派生类提供自己的front_wheel实例,那么您将只需要在基类中提供virtual访问器,并让派生类创建自己的访问者。

答案 2 :(得分:1)

变量front_wheel未被覆盖 - 它只是隐藏。成员变量Wheel front_wheel仍在Mountainbike类中。实际上,front_wheel中有两个名为Mountainbike的变量。但要访问Mountainbike中的隐藏变量,您需要明确说明:Bike::front_wheel

更好的做法是创建一个没有数据的接口类:

class Bike {
public:
  virtual Wheel const &getFronWheel() const = 0;
  virtual ~Bike() {}
};

然后从中获得任何特定的自行车:

class RegularBike: public Bike {
public:
  virtual Wheel const &getFronWheel() const { return wheel; }
private:
  Wheel wheel;
}

class MtbBike: public Bike {
public:
  virtual MtbWheel const &getFronWheel() const { return wheel; }
private:
  MtbWheel wheel;
}

修改:不使用虚拟化,而是使用模板:

template<typename WheelType>
class Bike {
public:
  /* Common methods for any bike...*/
protected: // or private
  WheelType wheel;
};

然后你可以按照自己的意愿扩展自行车:

class RegularBike: public Bike<Wheel> {
   /* Special methods for regular bike...*/
};

class MtbBike: public Bike<MtbWheel> {
   /* Special methods for Mtb bike...*/
};

答案 3 :(得分:0)

您可以创建IWheel而不是Class Wheel的界面。

在MtbWheel类中创建OverRide方法。因此,无论谁想要覆盖此方法都可以覆盖此方法,否则请使用我们在MtbWheel类中实现的默认方法。通过使用它,您可以添加它的属性。

答案 4 :(得分:0)

解决方案是不要这样做。编写派生类需要仔细研究基类,然后仔细设计。魔术饼干不能代替知识和思想。而且,是的,我已经分担了这种错误,并因为粗心而踢我自己。