0

我需要使用 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,我只想向它“添加”属性。

编辑:是否有没有虚拟功能但使用模板的解决方案?

4

5 回答 5

4

front_wheelMountainbike课堂上的成员不会 覆盖 front_wheel,它会隐藏它。Mountainbike类实际上有两个front_wheel成员,但是Bike类中的一个被 in 中声明的那个隐藏了Mountainbike。这意味着如果Bike访问front_wheel,它将访问一个类型的对象Wheel,而当Mountainbike访问时front_wheel,它将访问一个类型的对象MtbWheel-但这两个轮子对象彼此不知道!

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

根据史蒂夫杰索普在下面评论中的建议,使用模板而不是使用多态性的替代解决方案是:

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

template <typename WheelType>
class Bike { WheelType front_wheel; };

class Mountainbike : public Bike<MtbWheel> { /* ... */ };

这样,在 front_wheel 上操作时不涉及任何虚函数。但是,这种解决方案需要考虑一些要点:

  • 对于您使用 Bike 的每个不同 WheelType,将创建单独的代码;如果您有许多不同的此类类型,则可能会导致代码膨胀。
  • 如果您有多个Bike具有不同 WheelType 参数的类派生,则它们没有相同的基类(请参阅 Steve Jessop 的评论和第 1 点),因此也不能以多态方式访问。
  • 您不能强制作为模板参数传递给 Bike的显式接口;WheelType只有隐式接口是由使用的方法和成员定义的Bike。然而,这应该没问题,因为编译器仍然可以验证隐式接口。
于 2012-09-12T11:42:24.123 回答
1

你没有压倒任何东西。您的派生类中仍然有 a Wheel front_wheel;。您可以通过m.Bike::front_wheel或类似的方式访问它。如果您希望派生类提供它们自己的实例化front_wheel,那么您只需要virtual在基类中提供一个访问器并让派生类创建它们自己的。

于 2012-09-12T11:42:34.543 回答
1

该变量front_wheel没有被覆盖 - 它只是被隐藏了。成员变量Wheel front_wheel仍在Mountainbike类中。所以实际上有两个名为front_wheelin的变量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;
};

然后,您可以根据需要扩展 Bike:

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

class MtbBike: public Bike<MtbWheel> {
   /* Special methods for Mtb bike...*/
};
于 2012-09-12T11:42:48.513 回答
0

您可以创建 IWheel 的接口而不是 Class Wheel。

在 MtbWheel 类中创建 OverRide 方法。因此,任何想要重写此方法的人都可以重写此方法,否则使用我们在 MtbWheel 类中实现的默认方法。通过使用它,您可以添加它的属性。

于 2012-09-12T11:45:35.310 回答
0

解决方案是不要那样做。编写派生类需要仔细研究基类,然后进行仔细设计。魔术饼干不能代替知识和思想。而且,是的,我也犯了这种错误,并且因为粗心大意而自责。

于 2012-09-12T12:48:41.373 回答