前段时间学习iphone开发,非常力不从心,很多C/C++的类库代码看不明白。大学的时候都学过C/C++,但是基本上忘光了,现在做C#开发,经常写出来一些性能低下的代码,究其原因就是原理掌握不扎实,乱用.net framework。有人说C/C++是内功,java/c#是剑法,我比较认同。大学的时候听别人说C/C++都过时了,所以后来就选择学了C#。做了几年C#开发才发现基础的东西是不会过时,除非哪天我们不用计算机了,计算机体系彻底改变了。这次下决心好好研读一本C++书籍,上网查了下,都比较推荐C++ Primer,正好手头也有一本,还是比较精彩的第四版。特别记得上大三的时候C++老师在课上说的话:C++这门课大家要好好学啊,这门课是真正会关系到大家以后找工作 ,以后的职业发展的。当时很不以为然,现在都java/c#, 谁还用这个。现在才明白!既然决定就开始吧。
第一章基础入门就略过。
第二章变量和基本类型
2.1 基本内置类型
bool 布尔型
char 字符型
wchar_t 宽字符型
short 短整型
int 整型
long 长整型
float 单精度浮点型
double 双精度浮点型
long double 扩展精度浮点型
整型:整数,字符,布尔值合称为整型。
short(半个字长),int(一个字长),long(两个字长)类型都表示整型值。(32位机器中int和long的字长通常是相同的)
字符类型:char 和wchar_t. char通常是单字节(byte)。wchar_t 用于扩展字符集,比如汉语,日语,不能用单个char表示的。
bool类型:0值算术类型代表false,任何非0值都代表true。
除了bool类型,整型可以是带符号signed,也可以是不带符号unsigned,默认都是signed ,要定义无符号必须制定unsigned。
C++中把负值赋给unsigned对象是完全合法的。其结果是该负数对该类型的取值个数求模后的值。
C++内置类型与其在计算机的存储器中的表示方式紧密相关,计算机以位序列存储数据,没一位存储0或者1,在这一级上存储器没有任何意义。让存储具有结构的最基本方法是用块处理存储。
块的确切大小因机器不同而不同,但通常是8位的块作为一个字节,32位或者4个字节为一个字(word).
大多数计算机将存储器中的每个字节和一个地址的数关联起来
如 7353212 0100110,左面是地址,后面是字节的8个位。
要让字节地址为7353212的字节具有意义,必须要知道存储在该地址的值的类型,一旦知道了该地址的类型,就知道了表示该类型的值需要多少位和如何解释这些位。
浮点型:float,double,long double分别表示单精度浮点型,双精度浮点型,扩展精度浮点型。float用一个字(32位)表示,double用2个字来表示,long double 用3个或4个字来表示 .
实际程序中float通常精度不够,只能保证6位有效数字,double型至少可以保证10位有效数字,能满足大多数需要。
书中建议:
执行整型算术运算时,很少使用short,short可能会隐含赋值越界错误,产生很大的负数。
char类型虽然是整型,但是通常char用来存储而不用来计算。
在大多数机器上使用int类型进行整型计算不易出错。int类型16位表示对大多数应用程序来说太小了。一般用 32位int或者long,
整型运算时,用32位表示int类型和64位表示long类型的机器上进行同样的运算用long类型进行计算付出的代价远高于用int, 所以选择类型时要根据程序细节,了解性能差异后决定。
决定浮点型就容易多了:使用double基本不会有错。双精度计算的代价相对于单精度可以忽略。有些机器,double类型比float类型还要快得多。long double提供的精度通常没必要。
2.2 字面值常量
整型字面值规则
十进制 :20
八进制 :024
十六进制:0x14
128u unsigned 1024UL unsigned long
1L long 8Lu unsigned long
不提倡使用小写字母l,容易跟1混淆
浮点字面值规则
3.14159F 12.3435L
布尔字面值和字符字面值
bool test = false;
'a'
转义字符
换行符 \n 水平制表符 \t
纵向制表符 \v 退格符 \b
回车符 \r 进纸符 \f
响铃符 \a 反斜杠 \\
疑问号 \? 单引号符 \'
双引号 \"
'\0'通常表示空字符
字符串字面值
"Hello world"
为兼容C语言,C++所有字符串字面值编译器都会自动在末尾添加一个空字符字面值。
2.3 变量
变量提供了程序可以操作的有名字的存储区。 C++中的每一个变量都有特定的类型,该类型决定了变量的内存大小和布局、能够存储于该内存中的值的取值范围以及可以应用在该变量上的操作集。
左值:可以出现在赋值语句的左边或者右边。
右值:只能出现在赋值语句的右边。
对象是内存中具有类型的区域。计算左值表达式会产生对象。
变量命名习惯
变量名一般用小写字母。
标识符应该使用有意义的名字。
包含多个词的标识符在每个词之间添加下划线,或者每个内嵌的词的首字母大写,例如:student_loan 或者studentLoan.
定义对象 ,初始化对象
定义 :int units_sold; 类型决定了分配给变量的存储空间的大小和可以在其上执行的操作。
初始化:C++支持两种初始化形式,复制初始化和直接初始化。
int ival(1024) 直接初始化。直接初始化更灵活,效率更高。
int ival = 1024 复制初始化。 使用=来初始化和赋值是两种不同的操作。
初始化多个变量
double salary=9999.99, wage(salary+0.01);可以用同一个定义中前面变量的值初始化后面的变量。
变量的初始化规则
内置类型初始化
在函数体外定义的变量都初始化成0,函数体里定义的内置类型不进行自动初始化。未初始化的变量容易引起运行问题,而且难以发现。
类类型初始化
没有初始化的默认使用默认构造函数进行初始化操作。如果没有提供默认构造函数则必须显示初始化,没有初始值是根本不可能定义这种类型的变量的。
声明和定义
变量的定义用于为变量分配存储空间,还可以为变量指定初始值,在一个程序中,变量有且只有一个定义。
声明用于向程序表明变量的类型和名字。定义也是声明,可以通过extern关键字声明变量名而不定义它。extern是说明变量定义在程序的其他地方。程序中变量可以声明多次,但只能定义一次。
extern int i 声明不定义。
int i 声明并且定义。
名字的作用域
C++中花括号界定作用域,名字从其声明点开始直到声明所在作用域结束都可见。
作用域可嵌套
std::string s1 = "hello";
int main()
{
int s1 = 42;//局部变量 s1定义屏蔽全局变量s1.
}
2.4 const 限定符
定义const对象必须初始化,因为const变量定义后就不能修改。
const std::string hi = "hello!";// OK.
const int i,j = 0 ; //error, i 没有初始化。
const 对象默认为文件的局部变量。
//file_1.cc
int counter;
//file_2.cc
extern int counter;
++counter;
2.5 引用
引用是一种复合类型,通过在变量名前添加&来定义,引用必须用与该引用同类型的对象初始化。
int ival = 1024;
int &refVal=ival; //OK
int &refVal2; // error:引用必须初始化。
int &refVal3 =10;//error:初始化必须是一个对象。
const 引用:指向const对象的引用。
const int &r =42//对于const引用这是合法的,对于非const引用,这样是不合法的。
2.6 typedef
typedef 用来定义类型的同义词:
type double wages;
typedef通常被用于三个目的:
为了隐藏特定类型的实现,强调使用类型的目的。
简化复杂的类型定义,使其更易理解。
允许一种类型用于多个目的,同时使得每次使用该类型的目的明确。
2.7 枚举
定义和初始化枚举
//input is 0,output is 1, and append is 2
enum open_modes {intput,output,append}; //默认第一个枚举成员赋值为0,后面的每个枚举成员赋的值比前一个大1。
枚举成员是常量。
每个enum都定义了一种唯一的类型。 open_modes mode = input;//OK open_modes mode = 0;//error
2.8 类类型
C++对类的支持非常丰富。类定义了类型的对象包含的数据和该类型对象可以执行的操作。
从操作开始设计类
每个类都定义了一个接口和一个实现。接口由使用该类的代码需要执行的操作组成。实现一般包括该类所需要的数据。实现还包括定义该类需要但又不供一般性使用的函数。
类定义后面紧跟着一个分号,这是很普遍的错误。
定义变量和定义数据成员存在非常重要的区别:一般不能把类成员的初始化作为其定义的一部分。在定义数据成员时,只能指定该数据成员的类型和名字。类是通过构造函数控制初始化。
用Class和struct关键字定义类的唯一差别在于默认的访问级别。默认情况下struct的成员是public,而class的成员是private。
设计头文件
头文件为相关声明提供了一个集中存放的位置。头文件一般包含类的定义,extern变量的声明和函数的声明。使用头文件带来的好处:保证所有文件使用给定实体的同一声明;当声明需要修改时,只有头文件需要更新。
头文件用于声明而不用于定义。因为头文件包含在多个源文件中,所以不应该有变量或函数的定义。
一些const对象定义在头文件中
预处理器
#include是C++预处理器的一部分。预处理器在编译器之前运行。#include指示只接受一个参数:头文件名。预处理器用指定的头文件的内容替代每个#include。
头文件经常需要其他头文件,使用头文件保护符来避免多次包含同一头文件
#ifndef SLESITEM_H
#define SLESITEM_H
类定义和相关函数
#endif
使用自定义头文件
#include <iostream>//标准头文件
#include "my_file.h" //非系统头文件。