从OOP的角度重看C++(三)——OOP的更多语言机制

从OOP的角度重看C++(三)——类属、静态变量和抽象类

        在上节《从OOP的角度重看c++(二)》中讲到了在面向对象中,仅有5个基本概念(类、对象、方法和消息传递,继承)是很不够的,在以类为中心的概念中,我们又扩展出了重置和过载这两个概念。在本节中,我们继续扩展,包括:类属类、数据成员值的共享以及没有实例的类(其实,这3个概念依然是以类为中心的)。

        首先,看类属这个概念。在第一次的博客中,我们从ADT这个概念中提到了类属(generic)这个概念。他是一种更高层次的抽象(类是对象的抽象,而类属类则是类的抽象),允许将类型作为参数的抽象结构。C++中体现类属的机制是 模板(template)。包含有 类模板和函数模板。类模板的一个重要作用是对类库提供了强有力的支持。

       首先我们主要探讨一下类模板。类模板的定义格式为:

template<calss C> calss name{} 在里面定义数据成员和成员函数的时候可以用类型参数C来定义。合法的模板参数有: 

a type 

a constant expression(a string literal is not acceptable)

the address of an object or function with external linkage

a non-overloaded pointer to member

从以上可以看出来,参数必须要是 有地址的!比如: constant可以但是string literal (字符串字面值)不行就是因为constant 在堆中存储,可以字符串字面值只有值没有地址!(因为常量在预处理的时候就已经展开成符号标识,是不占空间的;只有变量占用空间,constant类型的常量本质上是个只读变量)因为, 类模板产生类是在编译时而不是运行时!编译的时候是没有办法提前知道值的。

此外,参数列表可以声明多个形参,并且,先声明的形参可以立刻用来声明同一个参数表中的其他形参,比如 template <class T ,T def_val> class Count{// }.


可以继承。因为类模板也是类型。既可以继承其他类模板的实例,也可以继承其他类。比如: template<class T> class Vec: public Vector<T>{};甚至,在继承其他类模板实例的时候,可以讲自己实例化后得出的类型作为那个类模板的实参! 总之,在所有允许出现类的地方,都可以出现类模板的实例

        尽管类模板产生类和类生成对象很像,但是他们是不同的:

类模板产生类必须要与用这个类产生对象同时进行。这是因为类模板没有名字,么有名字就意味着没有存储空间;这归根结底还是刚才说的它产生类是在编译时而非运行时。(这里有个细节问题,对类属类的实例化编译,一般是滞后到链接时才进行的。因此,如果类属类本身发生了修改,就需要编译那些与该类属类实例化相关的所有文件,因此在make文件中药定义相应的依赖关系)。

此外,对象的定义是:可以根据操作来改变状态。而类模板除了可以生成类以外,没有任何操作,这个类的结构是不可以改变的。

有了类模板的定义,老师当堂讲了一个例子,感觉超棒!要求使用类模板的定义来实现一个接口相同、按列存储的、任意元素类型的二维数组。答案如下(反正我不会,,)


从这里我们可以看出以下几个问题:

使用了friend,即限定了对外的访问控制,说明只有arrary 可以操作它,从实例的生成就设置了能见度控制;

在arraytmp和array之间传递的行号是通过icurrentrow来传递的;

充分考虑了取下标操作[ ]是二元操作符,因此才会这么麻烦的写一个arraytmp来

        从这里,我们可以看出: 不同层次(功能也许类似)的数据和操作,应当分离到不同的类/类模板中,再设计相应的关联结构和协同操作。数据成员对象也可以表示类之间的层次关系。在这里,我们把一个二维的数组拆成两个一维的数组去做就是这个意思,而传递行号的icurrentrow就是二者之间的关联结构。还有我们可以看出,简化操作的接口有利于理解和使用,但是需要更多的支持结构和操作,我们这里就是这样,为了方便取下标这个操作,设计了两个类。但是,设计复杂的接口也许操作会更容易,但是可用性却较差。(PS: 我在每次写博客的时候一方面是为了复习老师所讲的知识,做个记录,给像我一样的初学者参考;更主要的,我是希望从最最基本的概念里面找到优秀的设计思维)

        关于类属函数,实际中貌似用的并不多。需要注意的是,由于参数的不同,在里面使用和和参数相关的操作的时候,注意这种类型过载了这种操作,或者直接在参数列表中应用相应函数的指针,这样就避免了刚才说过的问题!课堂上有一点我记住了,就是自己写的排序算法再好,都没有库里面的好!为什么,请看他们的函数声明:

void qsort(const void* base, size_t nelem, size_t width, int (*fcmp)(const void* ,const void*))

       基于比较的排序算法中,我们不能确定待排序的内容都已经过载了 >,<,=这些操作符,所以,我们的参数列表中给出了一个函数指针来确保!不愧是库函数啊!想的真周到~

        数据成员只的共享,简单来说,就是这个类的所有实例都共享的数据,这个数据是以数据成员的方式出现的,在C++中就是静态数据成员(static)。一方面他支持了对象共享数据的情况,同时又具备了数据成员的特征。

        没有实例的类。在OOP的发展之初,应该是没有的;但是有了继承之后,就可以了,因为,可能需要在类层次结构较高的层次上存在着始终没有实例的类。在C++中,抽象类(abstract classes)就是干这个的。他的定义是;至少含有一个纯虚拟函数类(纯虚拟函数的定义是:不用也不允许定义方法体的虚拟函数)。他对于软件结构设计的作用是:规范了一组语义允许不同,语法必须应该相同的操作接口

        从我们上面的讲述来看,数据成员的共享和抽象类, 都有一箭双雕的作用!!这种设计思维是我们最应该学习的!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值