c ++中的面向对象,继承和组合

时间:2011-08-19 06:21:21

标签: c++ oop

有4个类:A,B,C和D. A类“有A”B,C类“有A”D。碰巧,C“是A”A,D“是A “B.在C ++中建模这些关系的最佳方法是什么?

A所拥有的B与C具有的相同。

示例:建筑物有入口,房屋有门。房子是建筑物,门是入口。

4 个答案:

答案 0 :(得分:3)

class B {
};
class A {
  B b;  // A "has a" B
};
class C : public A  { // C "is a" A
  D d;  // C "has a" D
};
class D : public B { // D "is a" B
};

答案 1 :(得分:1)

我认为你的设计存在缺陷。如果我理解正确,您希望限制基类成员变量的类型:

struct Entrance {};
struct Door : public Entrance {};

struct Building
{
    Entrance * entrance; // raw pointer just for the sake of clarity
};

struct House : public Building
{
    // Building::entrance must always be a door
};

你可以使用访问者(getter / setter)来实现entrance并检查类型,如果入口不是门,则抛出异常,但这会破坏Liskov substitution principle:你不会能够操纵House s,好像它们是Building s:

struct Drawbridge : public Entrance {};

House house;
Drawbridge bridge;

Building & building = house;
building.setEntrance(bridge); 
// Oups, I'm trying to install a drawbridge on my house!

有些库执行这种限制(例如,ReadOnlyCollection<T>在尝试修改其内容时会抛出异常),但在我看来,这不是一个简洁的设计。如果集合的界面声明我可以add元素到集合,那么只读集合集合(因为它不支持添加元素)。

此处可以应用相同的推理:House 一个Building,因为它不能包含所有类型的Entrance

答案 2 :(得分:1)

  

建筑物有入口,房子有门。房子是建筑物,门是入口。

struct Entrance        {};
struct Door : Entrance {};

struct Building {
   virtual Entrance& getEntrance() = 0;
};

struct House : Building {
   virtual Entrance& getEntrance() {
      return entrance;
   }

   private:
   Door entrance;
};

typedef Building A;
typedef Entrance B;
typedef House    C;
typedef Door     D;

这是使用多态性的最接近的近似值。请特别注意,Building无法实例化,因为它是“抽象的”。

否则,你不能A有一个B C有一个DBD都是同一个对象。


如果您想尝试让基座持有参考,请避免使用它:

struct Entrance        {};
struct Door : Entrance {};

struct Building {
   Building(Entrance& e) : e(e) {}
   Entrance& e;
};

struct House : Building {
   House() : Building(e) {}
   Door e;
};

typedef Building A;
typedef Entrance B;
typedef House    C;
typedef Door     D;

由于House的{​​{1}}构造函数在其创建Building之前被调用,这充其量是可疑的(并且在最坏的情况下未定义...我'我必须查阅它。)


然而,卢克是对的,这种模型是有缺陷的。

答案 3 :(得分:0)

C扩展A和D扩展B. A在其定义中保存B对象,C包含D对象。 [Has-a] [Is-a]