OOP设计 - 受保护的成员不在自己的类中使用 - 但仅在子类中使用

时间:2016-03-24 06:11:04

标签: c++ oop

我有一个班级(名字为例):

class Animal
{
public:
  // some virtual methods
};

还有一些子类。

class Dog : public Animal
{
public:
  Dog(Map&);
  // methods - using m_Map
private:
  Map& m_Map;  
};


class Elephant : public Animal
{
public:
  Elephant(Map&);
  // methods - using m_Map
private:
  Map& m_Map;  
};

如您所见,在创建Dog和Elephant对象时,必须提供Map引用,并且这些类使用它。动物(狗,大象,老鼠,猫等等)有很多类似的子类 - 都使用Map对象。

Animal的所有子类都使用Map对象,我在考虑将它作为受保护成员添加到Animal类是否是个好主意,例如:

class Animal
{
public:
  Animal(Map&);
  // some virtual methods
protected:
  Map& m_Map;
};

class Dog : public Animal
{
public:
  Dog(Map& map) : Animal(map);
  // methods - using Animal::m_Map
};

class Elephant : public Animal
{
public:
  Elephant(Map& map) : Animal(map);
  // methods - using Animal::m_Map  
};

但是,Animal类永远不会使用Map对象,所以对我来说,在这里存储它有点不自然 - 仅用于子类的使用。

另一方面,Animal的所有子类都将使用Map对象 - 因此最好在Animal类中指明它。而且当我在所有子类中将其定义为成员时,我也感觉代码是重复的。

你怎么看? Map对象是应该在所有子类中定义为成员,还是仅在Animal类中定义?

3 个答案:

答案 0 :(得分:2)

这取决于动物和地图之间的语义联系。

由于您使用的是C ++,因此可以使用多重继承。

首先,实现MapWrapper类:

class MapWrapper {
  private:
    Map *theMap;
  public:
    ...
};

然后像这样构建你的动物:

class Dog : public Animal, private MapWrapper {
};

请注意,private继承不是泛化/专门化,只是实现某种强大组合的技巧。

另一种可能性是在AnimalDog之间引入中间类。 Animal可能是纯粹的抽象类或契约,因此出于实用目的而修改它可能是不公平的。只需介绍AnimalMap

class AnimalMap : public Animal {
  // everything for the map
};
class Dog : public AnimalMap {
};

答案 1 :(得分:0)

如果基类型的所有派生类型都需要变量或函数,那么该变量或函数应该是基类型的一部分。这是继承的前提 - 以逻辑和系统的方式重复使用代码。

你提到你正在努力解决Animal对象永远不会真正使用Map的事实。您是否考虑过将Animal作为抽象类的类型层次结构的设计?这意味着Animal永远不会被实例化。在给定的例子中,这在概念上是有意义的 - 没有动物是动物;动物的类别包括许多其他更具体的概念,如狗或猫。

我建议这个实现适合你的例子并解决你的哲学难题。

答案 2 :(得分:0)

map对象只能在动物类中定义。为什么因为你继承了所有子类的动物类属性。

这是一个优势,您可以为动物类创建对象,并且您可以访问地图,直到您在动物类中没有任何纯虚拟方法

当谈到一个对象的内存大小时,无论是在基类还是派生类中,你持有地图都没有区别。派生对象的大小只相同

class animal
{
        public:
                int animal_id;
                int animal_age;
};
class dog :public animal
{
        public:
                int dog_type_id;
};
int main()
{
        dog d1;
        animal a1;
        cout<<"sizeof d1:"<<sizeof(d1)<<endl;
        cout<<"sizeof a1:"<<sizeof(a1)<<endl;
        return 0;
}