——分门别类是简化事物最有效的方式。

C++语言的强大能力的体现在对程序员自定义数据类型的支持。C++语言主要的一个设计目标就是让程序员自定义的数据类型像内置类型一样好用。

一、自定义数据类型

数据类型告诉我们数据的意义以及我们能在数据上执行的操作。因而自定义数据类型把数据及其对应操作组合在一起。

类的定义形式:

class ClassName

{

//数据

//操作

};

二、类的实例化方式

如何实例化一个类呢?最简单直接的方式就是模具铸造技术。就是把类的定义作为一个模具,铸造出一个个对象。这种方式最直接,也最容易理解,但效率却不高。那么应该如何实例化呢?其实也很简单,同中国的活字印刷术一样,只需要稍微转变一下观念。何必非要坚持对象的内容在物理上的连续性呢,只要对象的内容是完整的,就足够了。因而我们的眼中不再是一页一页的文字(类),而是一个个字(类成员)。

1、按照这种思路,可以把类成员抽象为两种类型

1) 同一类型的所有实例都相同的类成员

这种类成员,一个程序中保存一份就足够了。

2) 同一类型的各个实例不相同的类成员

这种类成员,每个对象都需要一份,以便呈现自己的独特风采。

2、数据成员与成员函数的实例化

(1)数据成员

按照上述对类成员的抽象,数据成员被区分为两类:

1) 属于类的数据成员(static)

一个程序保留一份即可,由类进行初始化。

2) 属于对象的数据成员(默认状态)

每个对象包含一份,由每个对象进行初始化。

(2)成员函数(方法)

其实对于同一类型的所有实例,它们所具有的方法是相同的,即方法只属于类,而不独属于某个对象,因而一个程序中具有一份就足够了。然而由于数据成员具有两种类型,因而C++根据方法对数据成员的操作方式的不同,分为两种类型:

1) 不可以直接(其实并不是真正的直接,下面会谈到)操作属于对象的数据成员(static)

2) 可以直接操作属于对象的数据成员(默认状态)

试图把数据成员和成员函数的分类统一起来,其实反而会带来更多的困扰,因为它们的分类依据本来就不相同。成员函数的分类依据其实很简单,就是this参数(隐式参数)的声明形式不同而已。

1) 常量成员函数(const)

const ClassName *const this;//指向常量对象的常量指针

因而常量函数不能改变对象的数据成员,常量对象不能调用非常量函数(this形参无法初始化)。

2) 静态成员函数(static)

没有声明this参数,因而不可以通过this指针操作对象的成员。

3) 普通成员函数(默认状态)

ClassName *const this;//指向普通对象的常量指针

从这里我们可以看出,本质上,成员函数和其他的函数并没有什么不同(仅仅书写形式上不同而已),都需要借助参数来访问函数之外的对象。

三、读写属性的控制

仅仅把数据和操作简单地组合在一起,还不能称之为是一个真正的类,只能称之为一个代码的集合而已。还需要添加对成员的读写权限。对于自定义类型,C++语言把类的成员的读写属性抽象为两个级别。

1、 特殊读写属性(可见性)的控制

成员的可见性(可见性是对于类外而言)是读写属性中比较特殊的一种,它区分了类内和类外,达到了对数据的封装。成员的可见性具有两个状态(暂不考虑继承,其实有了继承也不过是再增加一个protected而已。):

1) 可见(public)

2) 不可见(private)

为了代码的清晰,C++语言不再依赖默认状态,允许以更明确的方式控制成员的可见性。

2、 普通读写属性的控制

普通级别的读写属性控制和普通变量一样,是专门针对数据成员的。由类的实例化方式可知,无论是类外还是类的成员函数,其实都是通过对象以间接的方式访问其数据成员。因而都是典型的二层结构。

如图A是一个类对象,A包含3个public权限的数据成员:a、b和c。

对于对象A,它和普通变量一样,用const声明其为常量对象,用默认状态声明其为非常量对象。当A为一个常量对象时,相当于在对象的最外层镶了一层特殊的铁皮,只能通过A对A中的数据成员进行读操作,而不能进行写操作。如果变量a、b和c都是默认读写状态,声明A为常量对象就相当于(实际上并不等同,因为常量属性只施加在了外层对象上,只要突破了这层保护,该声明也就没有意义了。)变量a、b和c都是常量了。这样很不灵活,无法对数据成员的读写属性进行精细化控制,因而C++允许类的数据成员具有三种读写状态:

1) 总是仅可读(const)

2) 总是可读写(mutable)

3) 与类对象的声明一致(默认状态)

这样,我们就可以对任一个数据成员施加我们期望的读写权限了。

四、类型间沟通的门户

我们把事物分割在一个个相互隔离的框架内,既是为了简化问题,也是为了安全。但不同事物间是需要沟通的,因而C++语言在设置了一个个条条框框之后也开辟了几个门户,以达到沟通的目的,同时又可以设置重兵监督把守。

C++语言中的门户主要有以下几种:

1) 类型转换

通过定义转换构造函数,可以实现不同类型间的转换。但需要注意的是,与内置数据类型不同,一般的类型之间并没有那么强的联系,因而类型转换往往是没有必要的,而且会带来很大的安全风险。因此,通常情况下,应该抑制类型间的转换,把转换构造函数声明为explicit。

2) 成员函数

上面说到了,类型转换是危险的,而且往往是没有必要的。当两个类型间只有一种操作有联系时,定义一个函数应该是最合适的。

3) 友元

类的公共接口的设计应当是满足用户最常见的一般性需求。但是有一般的用户,肯定就有一些需求刁钻的用户。为了满足所有用户的需求,而把类设计得异常庞大是没有必要的。于是C++提供了友元,授予友元对类的所有成员的访问权限。通过友元,你可以如设计成员函数一样,设计出满足自己需求的高效接口,同时又不改变类的一般结构。可以说,友元提出的初衷是非常好的,但是这种不负责任的态度却也是危险的——你给别人开了后门,然后就理所当然地撒手不管了,那么有心人就可能背地里干些坏事了。

C++语言中的类型(二)的更多相关文章

  1. 以杨辉三角为例,从内存角度简单分析C语言中的动态二维数组

    学C语言,一定绕不过指针这一大难关,而指针最让人头疼的就是各种指向关系,一阶的指针还比较容易掌握,但一旦阶数一高,就很容易理不清楚其中的指向关系,现在我将通过杨辉三角为例,我会用四种方法从内存的角度简 ...

  2. C语言中如何将二维数组作为函数的参数传递

    今天写程序的时候要用到二维数组作参数传给一个函数,我发现将二维数组作参数进行传递还不是想象得那么简单里,但是最后我也解决了遇到的问题,所以这篇文章主要介绍如何处理二维数组当作参数传递的情况,希望大家不 ...

  3. C语言中不同类型的循环(Different types of loops in C)

    C语言中有三种类型的循环:for,while,do-while. while循环先判断循环条件. while (condition) { //gets executed after condition ...

  4. C++语言中的类型(一)

    --分门别类是简化事物最有效的方式. 类型是C++语言的基础,对象类型决定了能对该对象进行的操作. 一.基本内置数据类型 C++预先定义的基本内置数据类型是构造世界万物的原子,数据类型告诉我们数据的意 ...

  5. C语言中的指针(二)

    指针指向谁,就把谁的地址赋给指针,指针变量和指针指向的内存变量是不一样的.不停的给指针赋值,相当于是不断的改变指针的指向. 在开发中要避免野指针的存在,在指针使用完毕之后,记得要给指针赋值成为NULL ...

  6. C#语言中的类型转换方法(unfinished)

    一.C#中的数据类型 1.数值类型 2.字符类型 3.字符串类型 4.布尔类型 5.枚举类型 6.Object类型 二.常见的类型转换 从转换方式的角度,类型转换分为隐式转换与显式转换两种. 其中,隐 ...

  7. php弱类型语言中的类型判断

    1.php一个数字和一个字符串进行比较或者进行运算时,PHP会把字符串转换成数字再进行比较.PHP转换的规则的是:若字符串以数字开头,则取开头数字作为转换结果,若无则输出0. 例如:123abc转换后 ...

  8. C语言中不同类型的数据转换规则

    不同类型数据间的混合运算与类型转换 1.自动类型转换 在C语言中,自动类型转换遵循以下规则: ①若参与运算量的类型不同,则先转换成同一类型,然后进行运算 ②转换按数据长度增加的方向进行,以保证精度不降 ...

  9. 关于C语言中不同类型数据进行计算 有符号和无符号数进行计算

    float是8个有效位, 做个试验: 输出如下: 上面说明了什么: 1, 18/2.2 是除不尽的, 因为是define,所以没有给ratio变量赋值类型,但是从sizeof输出的结果是8,所以系统默 ...

随机推荐

  1. win10 UWP读写文件

    C# uwp应用的文件读写最常见错误就是没有权限. 而最简单的方法是对已知的文件路径进行访问 已知的文件路径常见的是自身的路径 权限这个和之前不同,UWP读写文件多用StorageFile来读写文件 ...

  2. Python基础3切片,字符串的方法

    切片:截取字符串某一段字符,并不改变原字符串.结构:[起始位置:终止位置:步长]  但不包括终止位置.所谓:顾头不顾尾 索引:序列中每个元素都是有编号的,都是从0开始编号的.使用负数索引时,Pytho ...

  3. eclipse远程调试Linux环境下的web项目

    前提: 远程服务器上的代码和本地的代码同步 第一步 : 配置远程服务器下的startup.sh文件 在第一行添加 : declare -x CATALINA_OPTS="-server -X ...

  4. java字串加密

    字串加密 1.设计思想: (1)加密方法,字符串的每一个字符都代表这个字符往后的第三位,最后三个字符代表,开始的三个字符. (2)解密方法,字符串的每一个字符都代表这个字符往前的第三位,开始三个字符代 ...

  5. [poj1644]放苹果

    题目链接:http://poj.org/problem?id=1664       把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5, ...

  6. 在vmware 中使用桥连接 连接到网络

    vMware虚拟机以后,连不上网,通过ifconfig命令,查看结果,如图所示: 然后,我想尝试一下,在虚拟机中ping 本地物理机地址,结果如图. 总结起来,主要有4步: 1.使用chkconfig ...

  7. Android的主线程和子线程

    在一个Android 程序开始运行的时候,会单独启动一个Process.默认的情况下,所有这个程序中的Activity或者Service(Service和 Activity只是Android提供的Co ...

  8. python抽象篇:面向对象

    1.面向对象概述 面向过程编程:根据操作数据的函数或语句块来设计程序的. 函数式编程:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象编程:数据和功能结合起来,用称为对象的东西包 ...

  9. 1087: [SCOI2005]互不侵犯King

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4276  Solved: 2471[Submit][ ...

  10. 【开源】【前后端分离】【优雅编码】分享我工作中的一款MVC+EF+IoC+Layui前后端分离的框架——【NO.1】框架概述

    写博客之前总想说点什么,但写的时候又忘了想说点什么,算了,不说了,还是来送福利吧. 今天是来分享我在平时工作中搭建的一套前后端分离的框架. 平时工作大多时候都是在做管理类型的软件开发,无非就是增.删. ...