变量和基本类型
1. int和long的范围一致,-2147483648~2147483647,若超过int范围选用long long。
2. char在一些机器上有符号,一些机器上无符号,所以用char直接做运算,容易出错。
3. 执行浮点数运算,使用double,float精度不够,且二者计算代价相差无几,有些甚至double更快。
4. 浮点数赋值给整形变量时,不四舍五入,只保留整数部分。
给无符号数赋值超过其范围,结果是初值对于无符号数总范围取模后的余数
如unsigned char i = -1; // i = -1 % 256 -- 255
给有符号数赋值超过其范围,结果是未定义的。
5. 切勿混用有符号数和无符号数,因为有符号数会自动转成无符号数
如 int i = - 1; unsigned int j = 1; k = i*j;//4294967295
6. 字面值‘A’表示单独的字符A,字符串“A”表示一个字符数组,包括字符A和空字符(‘\0’);
如果两个字符串字面符紧邻,且仅由空格,换行符和缩进符分隔,则为一个整体
7. 对象是具有某种数据类型的内存空间
8. 初始化不是赋值,初始化是在创建变量时给它赋予一个初始值,而赋值是把对象的当前值擦除,给一个新的值代替。
9. C++11,花括号初始化得到了全面应用 ,称为列表初始化,如int i{1};
但若存在初始值丢失风险,如将double赋给int,编译器会报错
10. 若未被显式初始化,定义在函数之外的内置类型变量(全局变量)为0,定义在函数内部的初始值未定义,类对象由类确定。
11. 使用别处定义的变量则需要声明,如extern int j; 注意不要初始化,否则即为定义,会报错。
12. 变量命名规范:变量名用小写字符,类名开头大写,若标识符由多个单词组成,不同单词间要有区分(加下划线或大写)。
13. 嵌套作用域:如定义与全局变量同名的局部变量在其作用域内可覆盖全局变量,但不建议这样做。
14. 引用并非对象,只是为已有对象起一个新的名字,对其操作与对绑定的对象操作一致,必须初始化,且一旦定义之后,无法修改绑定对象,不能定义引用的引用以及引用的指针
指针本身就是一个对象,允许赋值和拷贝,在生命周期内可指向不同对象,不是必须初始化(注意赋值操作永远改变的是左边,例:p = &ival; 改变的是p,而*p = ival,则是改变的是*p),有指向指针的指针,以及指向指针的引用。
int *&r = p; //r为指针的引用,从右向左的阅读r的定义,则r为一个引用,故为指针的引用
15. void*是一种特殊类型的指针,可用于存放任意类型的对象的地址,但不可对其指向的对象直接操作
16. 有关const:
const对象一旦创建后值无法改变,所以const对象必须初始化
如果想在多个文件共享const对象,则需在定义前加extern
const对象的引用必须为const类型,称为常量引用,常量引用不可被用于修改其绑定的对象,但仅对可参与的操作做限定,对象仍可通过其他方式修改,即引用的对象本身可以不是常量。
同理指向常量的指针也必须为const类型,指向常量的指针不可被用于修改其指向的对象,对象仍可通过其他方式修改,即定义为const的指针指向的对象本身可以不是常量。
const 指针 (*const)说明指针本身是一个常量,即指向的位置不可以变,故必须初始化,能否依靠它对其指向对象进行修改与对象本身类型有关, 如:
const double *const p = &a; // 从右向左读,第二个const表明为常量指针,第一个const表明不可用其对a修改
即:指针本身是常量不可变 char *const pContent;
指针所指向的内容是常量不可变 const char *pContent; //注意*与const的位置关系
二者均不可变 const char *const pContent;
另附const总结链接:https://blog.csdn.net/eric_jo/article/details/4138548
字符串、向量和数组
1. string的输入:cin >> s(以空白分割:空格,制表符和回车), getline(cin, s) 以回车分割
2. string的size返回为无符号数,如n为负整数,则s.size() < n 为正,n会转成很大的无符号数
3.
4. 范围for语句若需改变对象的值需加引用,如for(auto &c : s)
5. 若循环体内包含向vector对象添加元素的语句,则不能使用范围for语句,因为范围for语句内不应改变其循环序列的大小
6. 箭头运算符(->)把解引用和成员访问两个操作结合在一起,即it -> mem等价于(*it).mem
7. 但凡使用了迭代器的循环体,都不要向迭代器所属的容器添加元素
8. 不可以用一个数组初始化另一个数组,不能用一个数组给另一个数组赋值,但vector可以
9. 关于数组的指针和引用,由数组的名字开始由里到外,从右向左读:
10.
11. string专门提供了c_str()子函数,返回一个C风格的字符串
12. 可以使用数组来初始化vector
如: int a[] = {1, 2, 3, 4, 5, 6}; vector<int> b(begin(a), end(a)); vector<int> c(a + 1, a + 4);
begin和end为标准库中的函数,类似与容器的同名函数。
13. 要使用范围for语句处理多维数组,除最内层的循环外,外面都必须为引用
表达式
sizeof : 对char或类型为char的表达式,返回为1;对引用返回引用对象大小;对指针,返回指针大小,在32位系统,任意指针求sizeof都是4;对解引用指针,返回指向对象大小;对空的类实例执行,由于必须为实例分配内存,返回为1;对具有构造和析构函数的空实例执行,返回也为1,若其析构函数为虚函数,则由于需要虚函数表,返回指针的大小;对数组执行,返回数组所占大小,若数组当作函数的参数进行传递,数组自动退化为指针;对string或vector执行,返回固定部分大小,不计算实际元素占用空间
语句
do while语句应该在括号包围起来的条件后面用一个分号表示语句结束。
函数
1. 实参类型必须与对应的形参类型匹配,但若实参可以转换成形参,执行调用时可隐式的转换。
2. 局部静态对象在定义时初始化,直到程序终止才被销毁,在此期间即使所在函数结束执行也不会有影响。
(可以通过不用返回值或是采用指针传递的方式修改一个值)
3. 函数声明无需函数体,仅用一个分号替代,故也可不写形参名字,但一般保留,更有助于使用者理解。
4. 在C++中建议使用引用类型的形参代替指针,如果无需更改引用形参的值,最好设置为常量引用形参
5. 如何让函数一次返回多个值?
(1) 定义新的数据类型,含多个成员 (2)传入额外的引用形参
6. const:
与其他初始化过程一样,实参初始化形参会忽略顶层const
即void f(const int i){ } (可以传入int或const int)和 void f(int i){ }属于重复定义函数
一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。
另附const总结链接:https://blog.csdn.net/eric_jo/article/details/4138548
7. 数组有两个特殊性质,不允许拷贝数组以及使用时会转换成指针,所以不能以值传递方式使用数组参数,传递数组时,虽然可以把形参写成类似数组的形式,实际上传递的是指向数组首元素的指针,为确保数组不越界:
(a) 使用标记指定数组长度,如字符串中的‘\0' (b)使用标准库规范,传递首元素(begin)和尾后元素的指针(end)
(c) 显示传递表示数组大小的变量
8. 若无法提前预知向函数传递几个实参,可编写处理不同数量实参的函数,C++11提供了两种方法:
(a) 如果实参类型相同,传递名为initilalizer_list的标准库类型
(b) 如果实参类型不同,编写特殊函数(可变参数模板)
另外,C++还有一种特殊的形参类型(省略符...),可用来传递可变数量的实参,但只可出现在形参列表的最后。
9. 在含有return语句的循环外面,应该再加一条return语句
10. 函数完成后,它所占用的存储空间也随之释放,故不要放回局部对象的指针或引用。
11. C++11新标准规定,函数可以返回花括号包围的值的列表
12. main函数允许没有return语句直接结束,编译器将隐式地插入一条返回0的return语句。
13. 同一作用域内函数名字相同,但形参列表不同,则成为重载函数(不允许只有返回值不同)
14. main函数不能重载
类
1. 类用于定义自己的数据类型,基本思想是数据抽象和封装,封装实现饿了类的接口和实现的分离,封装后隐藏了实现的细节。
2. 成员函数的声明必须在类的内部,它的定义既可以在类内部也可以在类外部。定义在内部的为隐式的inline函数,定义在外部的需要包含它所属的类名,使用作用域操作符说明其所属。
3. 成员函数通过一个名为this的额外隐式函数访问调用它的那个对象,当我们调用一个成员函数时,用请求该函数的对象地址初始化this。任何对类成员的直接访问都可以被看做this的隐式引用,this为一个常量指针,不允许修改this中保存的地址。
4. 默认情况下,this为指向非常量的常量指针,故不能再一个常量对象上调用普通的成员函数,C++允许在成员函数的参数列表之后加const,表示this为指向常量的常量指针,这样的成员函数叫常量成员函数。常量对象,以及常量对象的指针和引用都只能调用常量成员函数。
5. 若需返回调用函数的对象,直接return *this, 一个const成员函数如果以引用的形式返回*this,则它的返回类型为常量引用。
6. 编译器分两步处理类,首先编译成员的声明,然后才是成员函数体,因此成员函数体可以随意使用类中的其他成员而无须在意这些成员的出现次序。
7. 定义类相关的非成员函数,一般将声明与类声明在同一个头文件中。
8. 默认情况下,拷贝类的对象其实是拷贝对象的数据成员。
9. 构造函数:初始化对象的数据成员,只要对象被创建就会执行构造函数;
构造函数名字与类相同,无返回值,有一个参数列表(可能为空)和一个函数体(可能为空);
类可以包含多个构造函数,类似与重载函数;
不能被声明为const,构造函数可以向const对象写值,构造完成后,const对象才获得常量属性。
若无显式定义,则使用默认构造函数,无须任何实参,有类内初始值则用其初始化,否则默认初始化。
若既需要默认构造,也需要其他形式的,则使用scales() = default要求编译器生成默认的构造函数。
10. 在C++中使用访问说明符加强类的封装性,public的成员可在整个程序中被访问,private的成员可以被类的成员函数访问,但不能被使用该类的代码访问,封装了类的实现细节。
11. struct与class的差别:struct中成员变量和函数默认为public,而class中默认为private。
12. 类可以允许其他类或者函数访问它的非公有成员,方法是令其为它的友元(friend),需要在类内以friend做友元的声明,友元不是类的成员,不受区域访问控制符约束,最好在类定义开始或结束前集中声明友元,但这只表示访问权限,为了能够真正调用这个函数,需要在类外同一个头文件中专门对函数进行一次声明。
13. 友元不具有传递性,且可以只令某类的成员函数为友元。若想把一组重载函数声明为友元,需要依次声明。
14. 封装的两个重要优点:
确保用户代码不会无意间破坏对象的状态;具体实现细节可以随时改变,而无需调整用户代码
15. 类可以使用typedef定义某种类型在类内的别名,为public或private,需先定义后使用,故常出现在类开始的地方。
16. 构造函数初始化列表:
line::line(int start,int end):first(start),second(end) {}
若成员是const、引用或属于某种未提供默认构造函数的类类型,必须通过构造函数初始化列表为这些成员赋初值。
成员的初始化顺序与它们在类定义中的出现顺序一致,而与初始化列表中成员的出现顺序无关。
17. 若需要限制构造函数定义的隐式转换,应使用关键字explicit
explicit class_name(const int&);
explicit关键字只对一个实参的构造函数有效,需要多个实参的构造函数不能用于执行隐式转换。且只能在类内声明构造函数时使用explicit关键字,在类外部定义时不应重复。且explicit构造函数只能用于直接初始化。
如果使用等号(=)初始化一个变量,实际上执行的是拷贝初始化;
若不使用等号,则执行的是直接初始化。
17. 聚合类:
1. 所有成员都是public的
2. 没有定义任何构造函数
3. 没有类内初始值
4. 没有基类,也没有virtual函数
18. 前置constexpr关键字声明constexpr构造函数,用于生成constexpr对象及constexpr函数参数或返回类型,其必须初始化所有数据成员,其初始值或使用constexpr构造函数或是一条常量表达式。
注意构造函数不能是const的!
19. 类的静态成员static
类的静态成员存在于任何对象之外,对象中不包含任何与静态数据成员有关的数据。其类型可以是常量、引用、指针、类类型等。类似的,静态成员函数也不与任何对象绑定在一起,它们不包含this指针,故而静态成员函数不能声明成const的,且我们也不能再static函数体内使用this指针。
我们可以使用作用域运算符直接访问静态成员,但我仍然可以通过类的对象、引用或指针来访问:
static double num;
//声明string类中的静态数据成员numdouble a=String::num;
//通过类名直接访问静态成员String s; a=s.num;
//通过类的对象访问静态成员
不能在类的内部初始化静态成员(除const),必须在类的外部定义和初始化每个静态成员且只能定义一次。类似全局变量,静态数据成员定义在任何函数之外,因此一旦被定义,就将一直存在于程序的整个生命周期中。
double String::num=0;
//类外定义并初始化一个静态成员
可以为静态成员提供const整数类型的类内初始值,不过要求静态成员必须是字面值常量类型的constexpr,初始值必须是常量表达式。
static constexpr int cnum=10;
//在类内初始化,初始值必须是常量表达式
如果在类内提供了一个初始值,则成员定义不能再指定一个初始值了。但即使一个常量静态数据成员在类内部被初始化了,通常情况下也应该在类的外部定义一下该成员:
constexpr int String::cnum;
//类外定义,但初始值类内定义提供
静态成员可以作为成员函数的默认实参,因为静态成员独立于任何对象;但普通成员不行,因为普通成员的值本身属于对象的一部分。另外静态数据成员的类型可以是它所属的类类型,而非静态数据成员则受到限制,只能声明成它所属的指针或引用:
static String sstr;
//正确,静态成员可以是不完全类型String *pstr;
//正确,指针成员可以是不完全类型String str;
//错误,数据成员必须是完全类型
顺序容器