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

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. linux上redis安装配置及其防漏洞配置及其攻击方法

    Linux上redis安装: 需先在服务器上安装yum(虚拟机可使用挂载的方式安装) 安装配置所需要的环境运行指令:  yum -y install gcc 进入解压文件执行make 指令进行编译 执 ...

  2. EasyUI Dialog 窗体 布局记要

    通常在窗体里放置的都是表单,或者使用分栏(Tab)来陈列信息也是非常的好用.在这里特别记录一下在窗体里同时放置表单和表格的设计思路. 仅放置一个表单 通常 Dialog 里只放一个表单,而且表单的行数 ...

  3. 关于scanf 与 cin gets(),getline()......输入输出字符串的区别

    很对人对于字符串的输入输出一直是比较模糊的,今天总结一下几个常用的输入流符号对于输入字符串时的区别: 1.scanf(),首先 它遇到空格或回车键(\n)就会结束,并且会将回车符算入字符串中: 2.c ...

  4. event模拟数据库链接

    from threading import Thread,Event,currentThread import time e = Event() def conn_mysql(): count = 1 ...

  5. (转)spring事务管理几种方式

    转自:http://blog.csdn.net/jeamking/article/details/43982435 前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置 ...

  6. Java基础-Eclipse环境搭建(02)

    Eclipse工具 IDE(Integrated Development Environment)集成开发环境集成了编写功能,分析功能,编译功能一体化的开发软件. 调试功能等,其中编译在保存时运行(即 ...

  7. LeetCode 122. Best Time to Buy and Sell Stock II (买卖股票的最好时机之二)

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  8. Bootstrap的核心——栅格系统的使用

        前  言 絮叨絮叨 Bootstrap 是基于 HTML.CSS.JAVASCRIPT 的,它简洁灵活,使得 Web 开发更加快捷. 而栅格系统是Bootstrap中的核心,正是因为栅格系统的 ...

  9. Swift 之Protocol在cocoa中的使用范例搜集(一)

    protocol Reusable: class { static var reuseIndentifier: String {get} static var nib: UINib? {get} } ...

  10. angular指令中的preLink函数和postLink函数

    指令模板选项有complie和link两个字段,两者之间存在如下关系: 当compile字段存在时,link字段将被忽略,compile函数的返回值将作为link字段. 当compile不存在,lin ...