一、C++入门与基本数据类型
1.C++中,一个函数必须在函数声明后才能使用(被调用)。
2.C++函数声明总是由函数原型构成。
3.参数声明时,要指出其类型。
4.函数定义中的参数称为形式参数,简称形参。
5.调用函数时实际传递的值称为实际参数,简称实参。
6.在大多数计算机上,short int 表示2个字节长。short 只能修饰int,short int 可以省略为short。
7.long 只能修饰 int 和 double 。修饰为 long int(可以省略为long)时,一般表示4个字节,修饰 long double 时,一般表示10个字节。
8.unsigned 和 signed 只能修饰 char 和 int。一般情况下,默认的 char 和 int 为signed。实型数 float 和 double 总是有符号的,不能用 unsigned 修饰。
9.用 typeof(数据类型) 可以确定某数据类型的字节长度。
10.命名变量名的规则:
(1)不能是C++关键字。
(2)第一个字符必须是字母或下划线。
(3)不要超过31个字符。
(4)中间不能有空格。
(5)不能包含“ . ; , " ’ + - ” 之类的特殊符号。变量名中除了能使用26个英文大小写字母和数字外,只能使用下划线“ _ ”。
(6)变量名不要与C++中的库函数名、类名和对象名相同。
11.八进制以0开头,十六进制以0x开头。
12.十进制数有正负之分,八进制和十六进制数只能表示无符号整数。
13.指数形式:E或e的前面必须要有数字,且E后面的指数必须为整数。
14.字符是用单引号括起来的一个字符。’ \ddd ’ 表示1 ~ 3位八进制数, ’ \xhh ’ 表示1 ~ 2位十六进制数。
例:"\x07operating\tsystem\n" 中有18个字符。
15.C++中,字符串总是以’\0’结束。
16.“0” 与 ‘0’ 是不同的。
17.printf("%-5.3s",“Hello”);负号表示左对齐,5表示格式宽度,3表示截取字符串中3个字符。
二、表达式和语法
1.操作符优先级:算术运算符>关系运算符>逻辑运算符>赋值运算符
2./ 对于整型数是取整,对于浮点数是通常意义的除法。
3.% 只能对整型数进行操作,意义为取余。
4.算术类型转换总是朝表达数据能力更强的方向,并且转换总是逐个运算符进行的。
5.数据运算过程中自动进行的类型转换称为隐式类型转换。
6.强制转换又称显示转换,其语法是在一个数值或变量前加上带括号的类型名。也可以类型名后跟带括号的数值或表达式。如果类型名是带类型修饰的,则要给类型名加括号。
7.条件运算符(条件表达式)?(条件为真时的表达式):(条件为假时的表达式)。条件运算符可以嵌套。
8.if ( !n ) 等价于 if ( n == 0 )和if ( n ) 等价于 if ( n != 0 )
9.do-while循环中,while(继续条件)后面的分号不要忘记。
10.for语句的三个表达式都可省略,且表达式1,2,3都可以为任何表达式。
11.switch后面括号中的表达式只能是整型、字符型或枚举类型表达式。case后面的常量表达式类型必须与其匹配。
12.因为case语句起语句标号的作用,所以case与default并不改变控制流程。case常与break语句联用,以保证多路分支的正确实现。最后一个分支可以省略break语句。
各个case(包括default)的出现次序可以任意。在每个case分支都带有break的情况下,case次序不影响执行结果。
13.default语句是可选的。当default不出现时,则当表达式的值与所有常量表达式的值都不相等时,越过switch语句。
14.switch语句可以嵌套。
15.continue语句和break语句的区别是:continue语句只结束本次循环,而不是终止整个循环的执行;而break语句则是终止整个循环,不再进行条件判断。
三、函数
1.C++不允许函数定义嵌套,即在函数定义中再定义一个函数是非法。
2.一个程序将操作系统分配给其运行的内存块分为4个区域:代码区、全局数据区、堆区、栈区。
3.函数结束时,静态局部变量不会消失,每次该函数调用时,也不会为其重新分配空间。它始终驻留在全局数据区,直到程序运行结束。静态局部变量的初始化与全局变量类似,如果不为其显式初始化,则C++自动为其初始化为0。
4.内联函数也称内嵌函数,主要解决程序的运行效率。
5.重载函数至少在参数个数、参数类型或参数顺序上有所不同。
6.typedef定义的类型只能使之相同于一个已存在的类型,而不能建立新的类型,所以不能用typedef定义的类型名来区分重载函数声明中的参数。
7.默认参数在函数声明中提供,当又有声明又有定义时,定义中不允许默认参数。如果函数只有定义,则默认参数才可出现在函数定义中。
8.默认值可以是全局变量、全局常量,甚至是一个函数。但默认值不可以是局部变量,因为默认参数的函数调用是在编译时确定的,而局部变量的位置与值在编译时均无法确定。
9.内联函数是为了提高编程效率而实现的,它克服了用#define宏定义说带来的弊病。
10.goto和switch语句不应使控制从一个声明的作用域跳到该声明的作用域内,因为这种跳转越过了变量的声明语句,使变量不能被初始化。
11.全局变量、静态全局变量、静态局部变量都具有静态生命期。具有文件作用域的变量具有静态生命期。静态生命期的变量,若无显示初始化,则自动初始化为0。
12.在函数内部声明的变量或是块中声明的变量具有局部生命期。具有局部作用域的变量若为局部变量,则具有局部生命期,若为静态局部变量,则有静态生命期。具有局部生命期的变量驻在内存的栈区。具有局部生命期的变量若未初始化,则内容不可知。
14.三类编译预处理指令:#include,#define,#if。
include包含指令:让预处理器把一个源文件嵌入到当前文件中该点处。
define宏定义指令:建立常量,定义带参数的宏,还有一个有效的使用是在条件编译指令中。
15.条件编译指令有:#if,#else,#elif,#endif,#ifdef,#ifndef,#undef。
条件编译的一个有效使用时协调多个头文件。使用#undef可以取消符号定义,这样可以根据需要打开和关闭符号。
四、数组与指针
1.初始化数组的值的个数不能多于数组元素个数,初始化数组的值也不能通过跳过逗号的方式来省略。
2.初始化值的个数可少于数组元素个数。当初始化值的个数少于数组元素个数时,前面的按序初始化相应值,后面的初始化为0。
3.对于字符串的初始化,要注意数组实际分配的空间大小事字符串个数加上末尾的’\0’结束符。
4.数组的大小为n,而字符串的长度为n-1。
5.在定义时,也可以只对部分元素赋初始值而省略第一维的大小,但应分行赋初始值。
函数调用时,数组参数的实参为整型变量的地址;函数原型中,数组参数的形参为整型数组的首地址。
6.有一种从数组尾部跳到其头部的技巧是“加1求模”。
7.用&操作可以获取变量的地址,指针变量用于存放地址。
8.放在可执行语句中的指针之前,称为间接引用操作符,而其放在指针定义中时,称指针定义符。
9.非指针变量是不能用间接引用操作符的,因为只能作用于地址。
间接引用既可以用于右值,也可以用于左值。
指针变量初始化的值是该指针类型的地址值。
指针在使用前,要进行初始化。指针忘赋值比整形变量忘了赋值要危险的多。
指针iPtr++不是后移一位,而是后移了一个单位。
只有加法和减法可用于指针运算。
10.a[i] 等价于 (a+i) 等价于 iPtr[i] 等价于 (iPtr+i)
&a[i] 等价于 a+i 等价于 iPtr+i 等价于 &iPtr[i]
11.数组名本身是一指针,它的类型是指向数组元素的指针。
12.数组名是指针常量,区别于指针变量。所以给数组名赋值是错误的。
13.常量指针(指向常量的指针):在指针定义语句的类型前加const,表示指向的对象是常量。定义指向常量的指针只限制指针的间接访问操作,而不能规定指针指向的值本身的操作规定性。const int pi = &a;不能通过pi来修改a的值,但可以把pi指向另外一个变量。
14.指针常量:在指针定义语句的指针名前加const,表示指针本身是常量。在定义指针常量时必须初始化。char const pc = “asdf”;可以通过 pc来修改其内容,但不能改变指针值即指向另外一个变量。
15.常量指针常量(指向常量的指针常量):const int const cpc = &b;其中cpc和 cpc都是常量,不能作为左值进行操作。*
16.指针数组:一个数组中每个元素都是一个指针。char * proname[] = { “Fortran”, “C”, “C++” };
17.指针数组与二维数组是有区别的。字符指针数组的内存表示,指针所指向的字符串是不规则长度的。二维数组每一列的大小必须是一样的。
指针数组名是指向指针的指针(即二级指针)。
18.传递数组给函数就是传递指针给函数。传递指针数组给函数就是传递二级指针给函数。
五、类、构造函数、静态成员与友元
1.C++特点:抽象、封装、继承、多态。
2.::叫作用域区分符,指明一个函数属于哪个类或一个数据属于哪个类。::可以不跟类名,表示全局数据或全局函数(即非成员函数)。
3.不能对类的数据成员进行初始化。
4.由于类名是成员函数名的一部分,所以一个类的成员函数与另一个类的成员函数即使同名,也不能认为是重载。
5.成员函数必须用对象来调用。
6.一个类对象所占据的内存空间由它的数据成员所占据的空间总和说决定。类的成员函数不占据对象的内存空间。
7.类的作用域是指类定义和相应的成员函数定义范围。
8.如果一个非类型名隐藏了类型名,则类型名通过加前缀可用。如果一个类型名隐藏了一个非类型名,则用一般作用域规则即可。
9.C++规定,一个名字不能同时指两种类型。非类型名(变量名、常量名、函数名、对象名或枚举成员)不能重名。
10.C++规定与类同名的成员函数是构造函数,在该类的对象创建时,自动被调用。
11.构造函数没有返回类型,函数体中也不允许返回值,但可以有无值返回语句“return;”。
12.一个类定义中,类的数据成员可能为另一个类的对象。
13.如果一个类对象是另一个类的数据成员,则在那个类的创建所调用的构造函数中,对该成员(对象)自动调用其构造函数。
14.析构函数没有返回类型,没有参数,没有重载。只是在类对象生命期结束的时候,由系统自动调用。
15.析构函数以调用构造函数相反的顺序被调用。
16.无参的构造函数被称为默认构造函数。
17.C++规定,每个类必须有一个构造函数,没有构造函数,就不能创建任何对象。
18.若未提供一个类的构造函数(一个都未提供),则C++提供一个默认的构造函数,该默认构造函数是个无参构造函数,它负责创建对象,而不做任何初始化工作。
19.只要一个类定义了一个构造函数(不一定是无参构造函数),C++就不再提供默认的构造函数。即如果为类定义了一个带参数的构造函数,还想要无参构造函数,则需要自己定义。
20.静态对象和静态变量一样,文件作用域的静态对象在主函数开始运行前全部构造完毕。块作用域中的静态对象,则在首次进入到定义该静态对象的函数时,进行构造。
21.全局变量、静态数据、常量存放在全局数据区,所有类成员函数和非成员函数代码存放在代码区,为运行函数而分配的局部变量、函数参数、返回数据、返回地址等存放在栈区,余下的空间都被作为堆区。
22.从堆上分配对象数组,只能调用默认的构造函数,不能调用其它任何构造函数。如果该类没有默认构造函数,则不能分配对象数组。
23.如果你的类需要析构函数来析构资源,则它也需要一个拷贝构造函数。
可以直接调用构造函数产生无名对象。无名对象可以作为实参传递给函数,可以拿来拷贝构造一个新对象,也可以初始化一个引用的声明。
24.转换构造函数是定义含一个参数的构造函数。
25.运算符new分配堆内存,如果成功,则返回该内存的空间,如果失败,则返回NULL。所以每次使用运算符new动态分配内存时,都应测试new的返回指针值,以防分配失败。pName = new char[ strlen(pN) + 1 ];if ( pName != 0 ) strcpy( pName, pN );
26.声明为static的类成员便能在类范围中共存,称之为静态成员。
27.静态数据成员在类声明外分配空间和初始化。
28.公共静态数据成员可被类的外部访问,保护或私有静态数据成员只可被类的内部访问。
29.静态成员函数定义是类的内部实现,属于类定义的一部分。它的定义位置与一般成员函数一样。
30.一个静态成员函数不与任何对象相联系,故不能对非静态成员进行默认访问。
31.静态成员函数与非静态成员函数的根本区别:静态成员函数没有this指针,而非静态成员函数有一个指向当前对象的指针this。
32.在类里申明一个普通函数,标上关键字friend,就成了该类的友元,可以访问该类的一切成员。
33.友元声明的位置可在类的任何部位,既可以在public区,也可以在protected区,意义完全一样。友元函数定义则在类的外部,一般与类的成员函数定义放在一起。
34.一个类的成员函数可以是另一个类的友元。
35.整个类可以是另一个类的友元,该友元称为友类。友类的每个成员函数都可以访问另一个类中的保护或私有数据成员。
36.静态成员的static一词与静态存储类的static是两个概念,一个论及类,一个论及内存空间的位置以及作用域限定。所以要区分静态对象和静态成员。
六、多重继承与运算符重载
1.虚拟继承的虚拟和虚拟函数的虚拟没有任何关系。
2.多继承的构造顺序:一,任何虚拟基类的构造函数按照它们被继承的顺序构造。二,任何非虚拟基类的构造函数按照它们被继承的顺序构造。三,任何成员对象的构造函数按照它们声明的顺序调用。四,类自己的构造函数。
3.在继承关系中,基类的private成员不但对应用程序隐藏,甚至对派生类也隐藏。而基类的保护成员则只对应用程序隐藏,而对派生类则毫不隐瞒。
4.一个私有的或保护的派生类不是子类,因为非公共的派生类不能做基类能做的所有的事。
5.保护继承与私有继承类似,继承之后的类相对于基类来说是独立的。保护继承的类对象,在公开场合同样不能使用基类的成员。
6.当一个类是两个或多个基类的派生类时,必须在派生类名和冒号之后,列出所有基类的类名,基类间用逗号隔开。
7.派生类的构造函数必须激活所有基类的构造函数,并把相应的参数传递给它们。
8.在无继承的类中,protected和private控制符是没有差别的。在继承中,基类的private对所有的外界都屏蔽(包括自己的派生类),基类的protected控制符对应用程序是屏蔽的,但对其派生类是可访问的。
9.运算符是函数,除了运算顺序和优先级不能更改外,参数和返回类型是可以重新说明的,即可以重载。
10.C++规定了“ . 、:: 、. * 、-> 、?: ”这五个运算符不能重载,也不能创造新运算符。
11.operator++()是单目运算符,它含有一个参数。++d <=> d.operator++(); d++ <=> d.operator++(0)
12.C++规定: =,(),[ ],-> 这四种运算符必须为成员形式。
13.使用前增量,对对象(操作数)进行增量修改,然后再返回该对象。所以前增量运算符操作时,参数与返回的是同一对象。
14.使用后增量,必须在增量之前返回原有的对象值。为此,要创建一个临时对象,存放原有的对象,以便操作数(对象)进行增量修改时,保存最初的值。
15.转换运算符:operator 类型名();它没有返回类型,因为类型名就代表了它的返回类型,故返回类型显得多余。