c ++组合(has-a)问题

时间:2013-01-28 09:07:18

标签: c++ polymorphism containers smart-pointers

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

我完全赞同这个规则,这个规则主要使事情比我们使用继承更简单。

我有一个问题应该使用Composition来解决,但我真的很难这样做。

假设您有 供应商计算机 ,并且您有两种类型的产品:

  1. 离散产品 - 就像零食一样。
  2. 流体产品 - 就像饮料一样。
  3. 这两类产品需要在名为VendorCell的类中表示,该类包含单元格内容。

    这两种产品共享一些相同的属性(dm),如价格,数量等...... 也包含一些不同的属性。

    因此,在此处使用Composition可能会产生以下结果:

    class VendorCell {
    private : // default access modifier
        int price;
        int quantity;
    
        // int firstProductAttributeOnly
        // char secondProductAttributeOnly
    };
    

    正如您所看到的,注释行显示对于单个VendorCell,取决于包含的产品,这两条注释行中只有一行是重要且可用的(另一条仅与另一种类型 - 例如流体。)

    因此,我可能有一个里面装有零食的VendorCell,不需要它的第二个产品属性。<​​/ p>

    组合(对于VendorCell)是否是正确的解决方案?对于你们来说,有人会通过构造函数确定VendorCell类型并且一个DM(专用于其他类型的DM)将不会被使用(例如将其标记为-1)吗?&gt;

    谢谢大家!

2 个答案:

答案 0 :(得分:4)

你偏爱继承的一般规则是正确的。这里的问题是你想要一个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 >来重构此代码,以便您可以获得更好的界面(具有货币兑换功能,例如)

答案 1 :(得分:0)

您继承以便重复使用。

您为了重复使用而撰写。

如果您有不同的属性,那么您可能希望继承,否则撰写。

一些变化:

class ProductVariety {
public:
    virtual void display(Screen& screen) = 0;
};

实施:

class Liquid : public ProductVariety {
public:
    virtual void display(Screen& screen) {
        //...
    }
}

撰写变体:

class Product
{
    int price;
    int quantity;

    unique_ptr<ProductVariety> variety;
}