我需要使用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。从技术上来说,我并不高兴。
答案 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上操作时不会涉及虚函数。但是,有一些方面需要考虑这样的解决方案:
Mountainbike
且具有不同WheelType参数的类,则不具有相同的基类(请参阅Steve Jessop的评论和第1点),因此也不能多态访问。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)
解决方案是不要这样做。编写派生类需要仔细研究基类,然后仔细设计。魔术饼干不能代替知识和思想。而且,是的,我已经分担了这种错误,并因为粗心而踢我自己。