因为工作需要,又要开始写c++了,但是c++发展的比较快,上学的时候虽然写过不少,但是也没有一个系统的学习。
在换工作期间,打算重新开始系统性的学习c++。这本书是我工作之前买的,一直没有读过,用的版本应该是c++11。现在好像已经出到很后面的版本了,一些新的特性等之后再学吧。
另外,文章主要为自己学习所用,如果内容能对看客提供些许帮助,不胜荣幸。
本书共有18个大章节。外加一些附录内容。
会随着目录依次记录学习。但是一些非常基础的东西我应该会略过。
本章节包括:
- c,c++发展历史与基本原理
- 过程性编程和面向对象编程
- c++如何在c基础上添加面向对象概念的
- c++如何在c基础上添加泛型概念的
- 编程语言标准
- 创建程序技巧
略
这一张主要介绍了c++的发展历史,我大块跳过了。
OOP(面向对象编程)强调的是数据,试图让语言来满足问题的要求。其理念是设计与问题的本质特性相对应的数据格式。OOP程序设计方式首先设计类,准确表示了程序要处理的东西。OOP还有助于代码的可重用。
C++中,类作为一种规范,描述这种新型数据格式,对象是符合这种规范设定所创建的数据。
c++支持泛型编程编程模式。与OOP的目标相同,都是为了重用代码和简化抽象概念。
不同点是,OOP其强调编程的数据方面,但是泛型编程强调的是独立于特定数据类型 。
运行c++程序的具体步骤大体如下:

| C++实现 | 源代码文件的扩展名 |
|---|---|
| UNIX | C、cc、cxx、c |
| GNU C++ | C、cc、cxx、cpp、c++ |
| Digital Mars | cpp、cxx |
| Borland C++ | cpp |
| Watcom | cpp |
| Microsoft Visual C++ | cpp、cxx、cc |
| Freestyle Code Warrior | cp、cpp、cc、cxx、c++ |
C语言新增了诸如控制结构和函数等特性。
C++增加了对面向对象编程和泛型编程的支持。
ISOC++标准(C++98/03和C++11)为确保众多实现的兼容提供了基础。
本章节包括:
- 创建C++程序
- C++程序的一般格式
- #include编译指令
- main()函数
- cin输入
- cout输出
- C++注释
- 使用endl
- 声明和使用变量
- 定义和使用函数
C++语法的入口由函数头int main()开始。main()被启动代码调用,启动代码是编译器加到程序内的,是程序和操作系统的桥梁。
C语言中使用的写法是,int main(void),c++中淘汰了这种写法。这种写法等价于void main(),但是由于系统兼容性,应该尽量使用int main()的标准格式。
ANSI/ISO C++标准对于函数进行了更改,如果在最后没有加return 0的语句,那么会隐式加入这条语句,仅限于main()。
通常情况下,C++必须包含一个main()函数。
但是在一些特定的场景下,比如说编写一个动态链接库模块(DDL),由于DDL不是一个完整的程序,所以是可以没main()的;专用环境的程序,比如控制器芯片,可能不用main;一些编码框架,存在隐式的main。
C风格的注释是使用/**/,C++的风格是使用//。
应该尽可能用C++风格的注释,避免出现问题。
C++的预处理器会在程序进行主编译之前对文件进行处理,它处理名称以#为开头的编译指令。
例如,使用cin和cout需要包含#include
例如iostram这样的文件叫做包含文件,也叫头文件。
C语言的头文件中可能会使用扩展名.h,C++中可能会去掉.h而在前缀加上c,比如math.h改成cmath。而对于纯粹的c++库,则没有,比如iostream。
| 头文件类型 | 约定 | 示例 | 说明 |
|---|---|---|---|
| C++旧式风格 | 以.h结尾 | iostream.h | C++程序可以使用 |
| C旧式风格 | 以.h结尾 | math.h | C、C++程序可以使用 |
| C++新式风格 | 没有扩展名 | iostream | C++程序可以使用,使用namespace std |
| 转换后的C | 加上前缀c | cmath | C++程序可以使用,可以使用不是C的特性,如namespace std |
名称空间是C++的一项特性,旨在编写大型程序时,能够将不同厂商的代码进行组合。
比如说两个已经封装好的产品中都包含wanda()名称的函数,那么在调用时,编译器讲不知道所指代的版本。使用名称空间的话,能够将产品封装在一个名称空间单元中,可以直接调用。那么上面的例子中,一个厂商可以将命名空间命名为Micro,那么函数的全程就变成了Micro::wanda()。
使用这种方法,类,函数,变量是C++编译器的基本组件,被放置在名称空间std中。
由于多数用户不喜欢引入名称空间,所以using编译指令应运而生,使用using namespace std;可以让人们不用在语句前加std::。
但是这实际上是一种偷懒的方式,在大型项目中容易有隐患。更好的方式是,只使所需要的名称可用:
- using std::cout;
- using std::endl;
- using std::cin;
这样不必使用using namespace std便可以使用cin和cout。
当然,如果要使用其他定义,那么还需要加入using列表。
从概念上看,输出是一个流,即从程序流出的一系列字符。
cout的对象属性包括一个插入运算符(<<),表示将右侧的数据插入到流中。
cout << "Hello World";
重载运算符
其实是将一个字符串语句插入到了输出流中。
可能注意到,插入运算符(<<)很像左移运算符(<<)。其实这是一个运算符重载的例子。通过重载,不同的运算符将有不同的含义。
C语言本身也有一些运算符重载的情况,比如&既表示取地址,又表示与位运算。*表示地址引用,又表示乘法。C++扩展了运算重载符的概念,允许用户为自定义类型定义新的运算方式。
控制符endl
endl也是在头文件iostream中定义的,位于命名空间std中。
endl表示重启一行。诸如endl等对cout有特殊含义的特殊符号被称为控制符。
换行符
C++中还可使用C语言的旧版方式,使用\n。
和endl的一个差别在于,endl确保程序继续运行前刷新输出(将其立即显示在屏幕上) ;使用“\n”不能提供这样的保证,意味着在有些系统中,有时可能在输入信息后才会出现提示。
C++中使用了分号来表示语句的结尾。说明可以将一条语句放置在多行上。
源代码中的标记和空白
一行代码中不可分割的元素叫做标记,空格、制表符、回车统称为空白。
C++源代码风格
C++中使用声明语句来指出存储类型并提供位置标签。
比如int carr;提供了需要的内存和内存单元的名称。编译器来负责分配和标记内存的细节。
C++中,所有的变量都必须声明。在一些语言,比如basic中,可以在使用变量时创建变量,但是这样可能会出现拼写错误难以调试的问题,声明变量可以发现潜在的问题。
C++通常的做法是在使用变量之前进行声明。
赋值语句会将值赋值给存储单元。carr=25;其中=叫做赋值运算符。 C++中可以连续使用赋值运算符。
- int a;
- int b;
- int c;
- a=b=c=1;
赋值将从右向左进行。
cout << carr;
首先,cout将carr替换成当前值25,然后把值转换成合适的输出字符。
cout的智能行为源自C++的面向对象特性。C++插入运算符将根据后面数据类型相应的调整其行为。是运算符重载的一个例子。
C++将输入看做流入程序的字符流。
iostream文件将cin定义为一个表示这种流的对象。
cout可以一条语句输出多个值。
类是C++中面向对象编程的核心概念之一。
cout是一个ostram类对象,cin是一个istream类对象,也是在iostream中定义的。
类描述了一种数据类型的全部属性(包括可使用它执行的操作),对象是根据这些描述创建的实体。
就想函数可以来自函数库一样,类也可以来自类库。C++之所以这么流行,很大程度上就是因为存在大量支持UNIX,Mac和windows编程的类库。
比如C++中包含一个sqrt()的函数,可以返回平方根。
x = sqrt(6.25)
其中sqrt(6.25)被称为函数调用。sqrt称为被调用函数。6.25称之为参数。
在使用函数之前,C++编译器必须知道函数的参数类型和返回值类型。C++需要为每个使用到的函数提供原型。
比如,sqrt()的函数原型就像这样:double sqrt(double);
原型结尾的分号表明这是一条语句,是一个原型;如果省去分号,那么编译器将把这行代码解释为一个函数头。
不要混淆函数原型和函数定义。一般库文件中包含了函数的编译代码,而头文件中则包含了原型。
C++库函数存储在库文件中,编译器编译程序时,必须在库文件中搜索使用的函数。自动搜索哪些库文件,因编译器而异。
函数也可以接受多个参数,或者不接收参数。
int rand(void); void明确指出,该函数不接受任何参数。如果省略void,括号为空,C++会将其解释为一个不接受任何参数的隐式声明。
不需要返回值的函数,也可以使用void指定返回类型。
一般的格式为,在int main() 之前定义函数原型,在之后实现函数定义。
int main() 的返回值不是返回给程序的其他部分,而是返回给操作系统。通常约定,返回值为0时一位置程序运行成功,否则意味着出现问题。
因此,如果C++程序无法打开文件,可以将其设计为返回一个非零值。
另外,C++存在专属关键字,比如return,int,void等,这些关键字是不能够作为变量名的。
通常有以下几种方式能够让程序访问名称空间std:
C++语句的类型:
本章内容包括:
- C++变量的命名规则
- C++内置的整形——unsigned long, long, unsigned int, int, unsignrf short, short ,char, unsigned char ,signed char, bool
- C++11新增的整形:unsigned long long, long long
- 表示各种整形的系统限制的climits文件
- 各种整形的数字字面值(常量)
- 使用const限定符号来创建符号常量
- C++内置的浮点类型:float, double, long double
- 表示各种浮点类型的系统限制的cfloat文件
- 各种浮点类型的数字字面值
- C++的算数运算符
- 自动类型转换
- 强制类型转换
C++命名规则:
如果想要使用两个或者更多的单词组成一个名称,通常情况下是使用下划线将单词分开。
在C++所有主观风格中,一致性和精度是最重要的。
C++总共有10种整数类型可供选择。
描述存储的内存越多,整数值范围越大。
C++提供了一种灵活的标准,确保了最小长度,如下:
当前很多系统使用了最小长度,即short为16位,long为32位,但是不同的系统下int还是有多种选择。可能在一个系统中int为16位,另一个系统中为32位。
头文件climits中包含了关于整形限制的信息。定义了表示各种限制的符号名称,比如INT_MAX为int最大取值,CHAR_BIT为字节位数。
sizeof运算符支出,在使用8位字节系统中,int长度为4个字节,可对类型名和变量名使用sizeof运算符。
climits中的符号常量如下
| 符号常量 | 表示 |
|---|---|
| CHAR_BIT | char的位数 |
| CHAR_MAX | char的最大值 |
| CHAR_MIN | char的最小值 |
| SCHAR_MAX | signed char的最大值 |
| SCHAR_MIN | signed char的最小值 |
| UCHAR_MAX | unsigned char的最大值 |
| SHRT_MAX | short的最大值 |
| SHRT_MIN | short的最小值 |
| USHRT_MAX | unsigned short的最大值 |
| INT_MAX | int的最大值 |
| INT_MIN | int的最小值 |
| UNIT_MAX | unsigned int的最大值 |
| LONG_MAX | long的最大值 |
| LONG_MIN | long的最小值 |
| ULONG_MAX | unsigned long的最大值 |
| LLONG_MAX | long long的最大值 |
| LLONG_MIN | long long的最小值 |
| ULLONG_MAX | unsigned long long的最大值 |
climits文件中包含与下面类似的语句行:
#define INT_MAX 32767
其中#define和#include一样,也是预处理器编译指令。意思为将所有的INT_MAX替换为32767。修改后的程序将在完成替换之后再进行编译。
#define是C语言遗留下来的,C++可以使用const来创建符号常量。所以不会经常用#define
然而被设计成用于C和C++的头文件中,必须使用#define。
对变量初始化的方式:
使用字面值或者其他常量来赋值:
int a=b;
int a=14;
如果不赋值,可能会产生未知错误。
C++11中使用{}对变量进行赋值。
int emus{12};
int emus = {12};
int emous = {}; // 大括号为空表示0值
使用这种方法可以防范类型转换错误。通过使用C++的大括号初始化,可作用于任何类型。是一种通用的初始化语法。
可以使用unsigned关键字进行声明,表示无符号。
通常情况下使用int。
当有大型整数数组时,使用short有必要。
16位系统转到32微系统,int数组内存量会翻倍,但是short数组不受影响。
如果数字第一位为1-9,那么就是十进制。
如果数字第一位为0,第二位为1-7,那么就是八进制。
如果数字前两位为0x或0X,那么就是十六进制。
cout默认情况下是十进制输出的。(无论什么方式,在计算机中都是二进制数。)cout还提供了dec, hex , oct控制符,用于指示cout的输出格式。
- using namespace std;
- int a = 42;
-
- // 10进制
- cout << a<< endl;
-
- // 16进制
- cout << hex;
- cout << a<< endl;
-
- // 8进制
- cout << oct;
- cout << a << endl;
C++编译器除非有理由,否则数字都存储为int。(除非存不下,或者有特殊后缀指定)。
后缀为L表示为long常量。
后缀U表示为unsigned int常量。
后缀为LL表示为long long常量。
在美国最常用ASCII字符集。
C++支持的宽字符可以存储更多值。比如Unicode。
可以用cout.put(ch); 显示一个字符。意思为通过类对象cout使用函数put()。
对于特殊的字符,C++提供了转义序列。
Unicode提供了一种表示各种字符集的解决方案——为大量字符和符号提供标准数值编码,ASCII是Unicode的子集。
与int不同,char既不是没有符号也不是有符号,取决于编译器。如果想做微数值类型使用,那么unsigned char和signed char的范围是有差距的。0-255 和-128-127。
C++11中新增了char16_t和char32_t,均为无符号。
C++使用前缀u表示char16_t字符常量和字符串常量,比如u"C"和u"be good"。
C++使用前缀U表示char32_t字符常量和字符串常量,比如U"C"和U"be good"。
类型char16_t和/u00F6形式的通用字符名匹配。
类型char32_t和/U0000222B形式的通用字符名匹配。
非零值转为true;零值转为false.
使用const修饰的变量被初始化后,编译器不允许再修改值。
一种常见的方法是将名称首字母大写,表示为常量。另一种约定是将整个名称大写。
const之所以比#define好,首先,能够明确指定类型,其次,可以使用C++的作用域规则限制在特定函数或者文件;第三,可以用于更加复杂的类型。
浮点数可以表示小数部分。
计算机会对浮点数进行两部分存储,一部分表示值,另一部分表示对值放大或者缩小。
比如,34.1245和34124.5。第一个数表示为0.341245(基准值)和100(缩放因子);第二个数表示为 0.341245(基准值一样)和10000(缩放因子更大)。
缩放因子是2的幂,不是10的幂。
一种方法是使用常见的书写方式,比如1.56 , 0.13 , 8.0。
第二种是使用E或者e,比如2.5e+8 , 7e5 , 9.11e -32。
称为浮点数,就是因为小数点是可以移动的。
三种:float ,double , long double。
是按照可以表示的有小数位和允许的指数最小范围来描述的。
有效位是数字中有意义的位。
C++对于有效位数的要求为:float至少32位,double至少48位,long double至少和double一样。但是三种类型的有效位数可以一样多。
通常情况下,float为32位,double为64位,long double为 80/96/128位。
这三种类型的指数范围至少为-37到37.
在cfloat中可以找到系统的限制。
使用cout.setf(ios_base::fixed, iosbase::floatfield); 可以迫使输出使用定点表示方法,防止使用E表示法,并将程序显示到小数点后6位。ios_base::fixed, iosbase::floatfield为iostream中的常量。
通常情况下,浮点数会被保存为double,如果想保存为float,需要在后面加f/F后缀。
对于long double 可以使用L/l后缀。
1.234f
2.45E20F
20.2L
浮点数的优点在于表示的范围更宽。
缺点在于精度低,而且运算速度没有整数快。
C++提供了+ - * / %五种基本运算符。
C++自动执行很多类型转换:
在进行类型转换时,通常会将一个值赋给取值范围更大的类型。
但是将大值赋值给一个更小的类型时,可能会出现精度不够,超出范围等问题。
C++11的校验表:
简单说就是:
long long > long > int > short > signed char > bool
C++可以使用int(a)或者static_cast
auto可以让编译器根据初始值类型推断变量类型。
在处理复杂类型,比如stl库中的类型时,会很好用。
C++的数值类型,整数,浮点数,操作符,类型转换。