作为一名C++程序员,我学到的一个重要且必不可少的规则是组合优先于继承(http://en.wikipedia.org/wiki/Composition_over_inheritance)。

我完全同意这条规则,该规则比起使用继承来使事情简单得多。

我有一个问题,应该使用“合成”来解决,但是我真的很努力。

假设您有一个供应商机器,并且您有两种类型的产品:

  • 离散产品-如小吃。
  • 液体产品-像饮料一样。

  • 这两种类型的产品将需要在一个名为VendorCell的类中表示,该类包含单元格内容。

    这两种产品具有相同的属性(dm),例如价格,数量等等。但是也包含一些不同的属性。

    因此,在此处使用合成可能会导致以下结果:
    class VendorCell {
    private : // default access modifier
        int price;
        int quantity;
    
        // int firstProductAttributeOnly
        // char secondProductAttributeOnly
    };
    

    如您所见,注释行显示,对于一个单独的VendorCell,取决于包含的产品,这两个注释行中只有一个是有效的(另一条仅与另一种类型相关-例如,流体) 。

    因此,我可能有一个VendorCell,里面有小吃,不需要它的secondProductAttributeOnly。

    (对于VendorCell)组合是正确的解决方案吗?对你们来说似乎合适的是,有人将通过构造函数确定VendorCell类型,而一个DM(专用于另一种类型的DM)将根本不被使用(例如,将其标记为-1)?>

    谢谢大家!

    最佳答案

    您偏爱组成而非继承的一般规则是正确的。这里的问题是您需要container of polymorphic objects,而不是可以容纳所有可能产品的巨型集合类。但是,由于有了slicing problem,您不能直接保存多态对象,但是需要通过(最好是智能的)指针来保存它们。您可以通过(智能)指针直接持有它们,例如

    class AbstractProduct { /* price, quauntity interface */ };
    class AbstractSnack: public AbstractProduct { /* extended interface */ };
    class AbstractDrink: public AbstractProduct { /* extended interface */ };
    typedef std::unique_ptr<AbstractProduct> VendorCell;
    typedef std::vector< VendorCell > VendorMachine;
    

    您只需从AbstractSnack / AbstractDrink派生定义小吃/饮料
    class SnickersBar: public AbstractSnack { /* your implementation */ };
    class CocaColaBottle: public AbstractDrink { /* your implementation */ };
    

    然后您可以像这样插入或提取产品:
    // fill the machine
    VendorMachine my_machine;
    my_machine.emplace_back(new SnickersBar());
    my_machine.emplace_back(new CocaColaBottle());
    
    my_snack = my_machine[0]; // get a Snickers bar
    my_drink = my_machine[1]; // get a Coca Cola bottle;
    

    还有其他解决方案,例如Boost.Any,它使用包装类在内部保存指向多态对象的指针。您也可以通过将typedef替换为包含VendorMachine的单独类std::vector< VendorCell >来重构此代码,以便获得更好的界面(例如具有货币兑换功能)

    09-06 14:08