类的种类及作用

来源:互联网 发布:数据库缺省值 编辑:程序博客网 时间:2024/04/28 15:23

弄清编写的是那种类

第一: 值类。

如:std::vectior,std::pair,模仿的是内置类型。他有以下特征:

Herb Sutter & Andrei Alexandresuc认为有以下特征:

1. 有一个公用析构函数,复制构造函数和带有值语义的赋值。

2. 没有虚拟函数(包括析构函数)。

3. 是用作具体类,而不是基类。

4. 总是在栈中实例化,或者作为另一个类直接包含的成员实例化。

Bjarne Stroustrup认为:

代表着相对简单的概念,带着支持此概念的一组最基本的操作。他们的界面与实现都有一对一的关系,

都不想作为派生的基类。具体类型不适合放进某个相关类的层次结构中,每个具体类型都能独立地理解,极少参考其他类。总之,一个具体类型就是一个内部类型。自然,内部类型也都是具体的。

总体目标:

进可能紧密地与某个特定概念或者实现策略相匹配。

通过在线处理,让操作能够尽可能地利用概念及其实现的性质,提供相当于“手工打造”代码的运行时间与空间效率。

对其他类只有最小的依耐性。

能够独立地理解和使用。

为了以某个具体类型作为参数,函数就必须把确切的具体类型作为参数类型。这里并不存在继承关系,无法利用继承关系去减少参数类型的特殊性。正因为如此,如果企图利用具体类型间的相似性,就会涉及到模板通用性程序设计(p672)。

 

    这种类更经常被作为成员或者私用基类,在那些情况下可以有效地利用他们,又不会使其界面和实现与新类地界面和实现混合在一起使用,相互连累。

 

具体类型是以不修改的方式"重用",就像int一类的内部类型:
class Date_and_time{

private:

          Date  d;

         Time  t;

public:
    //……

};

这种形式的使用通常很简单、有效、效率也很高。

最后一个良好的具体类型可以用作另一个易塑造的类型的表示。

class Date3{

            public:

                     / /公用界面,基本上由虚函数组成

            private:

                     Date d;

};

这就是必要时将某个类(具体或是内部类型)纳入某个层次结构的方式。

 

 

 

 

第二:基类。

1.有一个公用且虚拟,或者保护而且非虚拟的析构函数,和一个非公用复制构造函数和赋值操作符。

2.通过虚拟函数建立借口。

3 .总是动态地在堆中实例化为具体派生类对象,并通过一个(智能)指针来使用。

Bjarne Stroustrup认为:使用抽象基类的原因有二。

一是淡化实现者与类的用户之间的联系。

二是淡化创建对象的代码和使用这种代码之间的联系。

因此,最简单便是引入一个抽象类:

template<class T>

class set

{

public:

    virtual  void insert(T*) = 0;

   virtual void remove(T*) =0;

   virtual int is_member(T*) = 0;

   virtual   T* first() = 0;

   virtual T* next() = 0;

   virtual ~set() = 0;

};

这就定义了一个集合的界面,带有一个内部的对元素迭代的概念。

template<class T> class List_set : public set<T>, private list<T> {

//……

}

template<class T>class vector_set : public set<T>,private vector<T>{

//……

}

对于具体类型,我们需要重新设计实现类去表达某些共性,使用模板去利用其中的共性。

而在这里,我们必须设计一个公共界面,但对于实现的那些类而言,除了需要实现界面的功能以外,再没有别

的其他的共性要求了。

为什么在我们在可以有抽象类型的时候还要有具体类型呢?

高效率。

重用:重用库而不是重写他们。

多重界面:为许多不同的类使用一个单一公共基类将导致肥大的界面。

通常更好的方式是为服务于新用途的类提供新的界面。

 

第三:traits类,是携带有关类型信息地模板。

1.只包含typedef和静态函数。没有可修改的状态或者虚拟函数。

2.通常不实例化(构造一般被静止)。

第四:策略类(比如模板),是可插拔行为的片段

1.可能有也肯能没有状态或者虚函数。

2.通常不独立实例化,只能作为基类或是成员。

第五:异常类。

1.有一个公用析构函数和不会失败的构造函数。

2.有虚函数。通常能实现克隆和访问。

3.从std::exception虚拟派生更好。

第六:结点

带着派生的观点去构造类层次结构与用于抽象类型的界面、实现观点很不一样。

 一般情况下,在类层次结构里的一个类表示一个具有普遍性的概念,其派生类可以看成是它的专门化。

被设计者作为某个层次结构中一个不可缺少的部分的典型类被称为结点类。它需要依靠基类的服务去提供一些服务,这就是说需要调整一些基类的成员函数。一个典型的结点类不仅提供了由基类刻画的界面的一个实现,还常常加入自己的新函数,这样就成为一个更宽广的界面。

比如:

class car : public vechicle{

public:

         car(int passengers,  size_category size, int weight, int fc):

          vechicle(passengers, size, weight), fuel_capacity(fc){     }

      //覆盖来自vechicle相关虚函数

         void turn (Direction );

       //……

      /增加car的特殊函数:

     virtual void add_fuel (int amount);

};

结点类与抽象类型最大的不同就在于次,他需要有比较复杂的构造函数。而抽象类型通常极少有构造函数。

对于car的基本操作通常需要在实现中使用基类vehicle提供操作。此外,car 的用户也依赖于来自基类的服务。

比如:car依赖于vehicle  。

     bool Bridge :: can_cross(const  vechicle & r)

   {

     if(max_weight < r.weight() )

      return false;

}

这就使程序员可以在结点类vehicle的基础上创建像car和truck这样的新类,他们只需要描述并实现与vehicle不同的东西。

这通常被称为“通过差异做程序设计”,或者通过“扩展做程序设计”。

car本身也可以更进一步派生:

    class ambulance : public car, public emergency{

    public:

             ambulance();

             //覆盖相关的car虚函数

            void  turn (Direction);

            //覆盖相关的emergency虚函数:

           virtual void dispatch_to(cost   Location&);

           //……

          //添加ambulance的特殊函数

         virtual int patient_capacity();  //担架数

         //……

};