复习10:类

来源:互联网 发布:讲文明知礼仪主题文章 编辑:程序博客网 时间:2024/05/29 17:52

10.1 引言

 

10.2 类

10.2.1 成员函数

10.2.2 访问控制

10.2.3 构造函数

        构造函数可以有多种重载形式,如:

10.2.4 静态成员

         静态成员--包括函数和数据成员--都必须在类外定义,如 注:在vs的编译器上静态函数成员可以在类内定义,但为了程序的可移植性不建议这样做。

10.2.5 类对象的复制

      按照默认的方式,类对象的复制就是其中各个成员的复制。如果对于类X这种方式不恰当,就需要定义一个复制构造函数(也成拷贝构造函数)X::X(const X&).

      类似的,类成员也可以通过赋值运算符进行按默认方式的复制。

10.2.6 常量成员函数

     常量成员函数表明它不会修改对象的状态。一切对象都可以嗲用cosnt成员函数,而const对象缺不能调用非const函数(这个很自然)。

10.2.7 自引用

      每一个非静态的函数都知道它在哪个对象里调用,因此可以显式地返回该对象。如 表达式*this引用的就是这个函数这次调用所在的对象。

在一个非静态的成员函数里,关键字this是一个指针,指向该函数所在的对象。在类X的非const成员函数里,this的类型是X*,在const成员函数里,this的类型是cosnt X*,防止修改该对象。在静态的成员函数里使用this是没有意义的,c++在静态成员函数里不设置这个关键字,即无法使用this。this并不是一个常规的变量,更不是一个左值变量,不能取得他的地址或给他赋值。

10.2.7.1 物理和逻辑的常量性

      偶然有这种情况,一个成员函数在逻辑上是const,但它却仍然要改变某个成员的值。对于延迟求值技术,这个问题更常见。比如成员函数要返回对象的某个性质,逻辑上它应是const函数,但是这个性质可能已经过期需要重新计算,这是该函数就需要先做修改后再返回新的值。我们可以通过const_cast把this的const属性去掉,这种不优美的方式存在着潜在的风险,如: 

10.2.7.2 可变的--mutable

      为了避免无定义的行为,只有将数据声明为mutable。存储描述符mutable特别说明这个成员需要以可以更新的方式存储--即使他是某个const对象的成员。这使得const集合中出现一些特例。 

      如果这些特例不是太多,使用mutable是最合适的。但是在一个对象在逻辑上保持为cosnt的同时,其中大部分都要修改,那么最好将这些需要修改的数据放入里外一个独立的对象里,并间接地访问它。

 

10.2.8 结构和类

      一个struct也就是一个类,但其默认成员是公用的。下面两个声明完全等价。

 10.2.9 在类内部的函数定义

      如果一个函数是在类定义的内部定义的,他就是一个在线成员函数。也就是说,在内部定义的成员函数应该是小的,频繁使用的函数。也可以在类外显式的声明一个成员函数是在线的。

 

10.3 高效的用户定义类型

        这里给出一段代码,我想讨论下其他方面的细节       这些细节的描述相当混乱,在此记下这些疑惑后来能有个清晰的解答。

      首先看下static变量。这里只讨论非局部的static变量(局部的static用法很简单,略去)。static变量存放在静态数据区,寿命为程序的整个运行过程,并收相关作用域的约束。使用sizeof求得的大小并不包括占用静态数据区的大小(这跟sizeof有关系,应该给深入的认识sizeof)。普通的递归定义是不允许的,因为编译器要知道每个类型的大小,以便在栈上给它分配空间,编译器无法计算递归定义类型的大小,所以这就被c++禁止了。但是对于static就不同了,static变量不在栈上分配,因此允许static形式的递归定义(在静态数据区上怎么分配呢?关于程序的内存布局还是很模糊,希望做个专题解决它)。

       现在说说对enum的看法,enum就是一个static const的变量,关于占用空间的大小和有效性已在前面讨论过了。类中enum成员属于类类型的一部分,不单属于某个对象。

10.3.1 成员函数

10.3.2 协助函数

      协助函数并非是类的成员函数,而是处理类常用的函数,如计算两个两个日期之间的天数,求一周后的日期等等。也可以将他们做为类的成员函数,但这样会使得类的界面复杂,可以考虑将这些协助函数和类放在同一个名字空间里。用户包含了该名字空间后就可以方便的使用他们了。

10.3.3 重载的运算符

10.3.4 具体类型的意义

      我们把像Date这样简单用户定义类型称作具体类型,是为了区别抽象类型和类层次结构,也是为了强调它们与int和char等内部类型的相似性。如果有一个非常好的编译器,像Date这样的具体类型将不会带来隐形的时间或者空间上的额外开销。具体类型的大小在编译的时候已知晓,可以在运行栈上分配存储。

 

10.4 对象

10.4.1析构函数

      一个类只能有一个析构函数,且析构函数是一个无参函数。当一个自动变量离开作用域时,当一个位于自由存储被删除时,还有在其他类似的情况中,析构函数将被隐式的调用。只有在非常特殊的情况下,用户才需要显式地调用析构函数。程序退出后它占用的所有资源(不含共享的资源)会被OS回收,包括自由存储区。

10.4.2 默认构造函数

      默认构造函数就是不需要提供参数的构造函数,包括无参的和带默认值参数的构造函数。一个类只有一个默认构造函数。如果用户声明了默认构造函数,那么就会去使用它;否则,如果有必要,而且用户没有声明任何构造函数,编译器就会设法生成一个。所以声明非默认构造函数时最好也声明默认构造函数,不然在默认构造函数被调用的时候就会产生错误。编译器生成的默认构造函数将隐式地为类类型(class type)成员和它的基类调用有关的默认构造函数,其他的似乎声明都不做。 这里将使用有编译器生成的默认构造函数生成tt,该构造函数为tt.t1以及tt.vt的每个成员调用Table(15)。另一方面,它不会去初始化tt.i和tt.vi,因为他们不是类类型的对象。这是为了与C的兼容和运行时的额外开销。

      由于cosnt和引用必须进行初始化,包含const或引用的类就不能进行默认构造,除非程序员显式地提供默认构造函数。内部类型的默认构造函数,参加6.2.8.

10.4.3 构造和析构

      一个对象可以通过以下方式建立和销毁:

10.4.4 一个命名的自动对象,程序执行时遇到它的声明时建立,离开它所在的块时销毁。即它生存在它的可见域中。

10.4.5 一个自由存储对象,通过new建立,通过delete销毁。

10.4.6 一个非静态成员对象,作为另一个类对象的成员,它随所属对象一起建立或销毁。

10.4.7 一个数组元素,随着所属数组一起建立或销毁。

10.4.8 一个静态局部变量,在程序执行第一次遇见他的声明时建立一次,在程序终止时销毁一次。

10.4.9 一个全局变量,名字空间的对象,类的静态对象,它们在main开始前建立一次,在程序终止时销毁一次。

10.4.10 一个临时变量,作为表达式求值的一部分被建立,在所属表达式结束时销毁。

10.4.11 一个在分配操作中所提供的参数控制,在分配函数获得的存储区里放置的对象。--稍后讨论

10.4.12 一个union成员,他不能有构造和析构函数。

下面将他们分到各个小节中具体讨论。

原创粉丝点击