请求提供简单的C++组合与继承示例

lmvvr0a8  于 2022-12-15  发布在  其他
关注(0)|答案(2)|浏览(105)

我试图理解C++中组合和继承之间的语法差异。
我希望有人能提供两个简单的例子,一个是使用复合的类,另一个是使用继承的类。

lskq00tm

lskq00tm1#

当然可以,为什么不呢?既然我喜欢机器人,那我们就做一个能到处走、能抓东西的机器人吧。我们用继承来做一个机器人,用组合来做另一个机器人:

class Legs {
public:
   void WalkAround() {... code for walking around goes here...}
};

class Arms {
public:
   void GrabThings() {... code for grabbing things goes here...}
};

class InheritanceRobot : public Legs, public Arms {
public:
   // WalkAround() and GrabThings() methods are implicitly
   // defined for this class since it inherited those
   // methods from its two superclasses
};

class CompositionRobot {
public:
   void WalkAround() {legs.WalkAround();}
   void GrabThings() {arms.GrabThings();}

private:
   Legs legs;
   Arms arms;
};

注意,至少对于这个例子,CompositionRobot通常被认为是更好的方法,因为继承意味着is-a关系,并且机器人不是特定种类的Arms,也不是特定种类的Legs(而是机器人has-armshas-legs)。

68de4m5k

68de4m5k2#

进一步扩展@jeremy-friesner的答案(并且主要是重用他的代码),很多时候组合是使用更多的类来实现的。本质上,Legs和Arms类是接口的实现。这使得很容易注入这些依赖项,因此,在单元测试组合对象时,可以模拟/清除它们。然后,你会得到类似的结果(忽略虚析构函数...):

class Walker // interface
{
public:
    virtual void Walk() = 0;
}

class Legs : public Walker
{
public:
    void Walk() {... code for walking around goes here...}
}

class Grabber // Interface
{
public:
    virtual void GrabThings() = 0;
}

class Arms : public Grabber
{
public:
    void GrabThings() {... code for grabbing things goes here...}
}

class InheritanceRobot : public Legs, public Arms
{
public:
    // Walk() and GrabThings() methods are implicitly
    // defined for this class since it inherited those
    // methods from its two superclasses
};

class CompositionRobot
{
public:
    CompositionRobot(Walker& walker, Grabber& grabber) 
        : legs(walker), 
          arms(grabber) 
    {} 
    void Walk() {legs.Walk();}
    void GrabThings() {arms.GrabThings();}

private:
    Walker& legs;
    Grabber& arms;
};

因此,用于腿部和手臂的实际实现可以在运行时而不是编译时设置。
顺便说一句,我只是把这作为一个答案,而不是对杰里米的答案的评论,以受益于代码格式,所以,如果你想投票,请做杰里米的了。
高温加热

2021年9月14日更新:

在这个答案中我注意到的一件事是,我把组合和聚合混为一谈了。在组合中,如果父对象不再存在,那么子对象也不再存在,而在聚合中,父对象被销毁后子对象可能还存在。我给出的描述是,其中在CompositionRobot构造函数中传递对子对象示例的引用意味着聚合关系而不是组合。然而,如果在定义参数和创建对象时使用std::unique_ptr(),而在将对象存储在CompositionRobot的构造函数中时使用std::move(),则效果与Jeremy的答案中的效果大致相同,在Jeremy的答案中,对象(而不是指向对象的指针或引用)被定义为类成员。

相关问题