C++拾遗

1三个概念
字符串字面值
是一串常量字符(是一个常量),字符串字面值常量用双引号括起来的零个或多个字符表示,为兼容C语言,C++中所有的字符串字面值都由编译器自动在末尾添加一个空字符。字符串字面值的类型就是  const char 类型的数组。标准库函数 strlen 用于计算 C 风格字符串中的字符个数, 不包括 null 结束符。

C++风格字符串:string

那么string a1=“hello”//这个就是string  string a2=a1+"world"//其中a1 是string “world”是字符串字面值

对string类使用c_str函数可返回返回指向字符数组首地址的指针,该数组存放了与 string 对象相同的内容,并且以结束符 null 结束,这样就可以把string类型当做c风格字符串来用了。在文件流的操作中,我们的文件名必须用C风格字符串,这样的话,常常就需要使用c_str()string类型的文件名转化为c风格字符串。

C风格字符串字符串字面值的类型实质是const char类型的数组。C++从C语言继承下来的一种通用结构是C风格字符串,而字符串字面值就是该类型的实例。 

使用操纵 C 风格字符串的标准库函数时,牢记字符串必须以结束符 null 结束


2 关于size_type
标准库类型将size_type定义为unsigned类型
string类型虽然任何整型数值都可作为索引,但索引的实际数据类型却是类型 unsigned 类型 ,实际上我们可以这么得到这种类型string::size_type
这是一种“配套类型”,可以使得库类型的使用与机器无关,size_type保存string类型对象的长度,在容器vector里面也有使用

在用下标访问元素时,vector 使用 vector::size_type 作为下标的类型, 而数组下标的正确类型则是 size_t(ps:与 vector 不同,一个数组不能用另外一个数组初始化,也不能将一个数组赋值给另一个数组


3指针的两种定义方式
一种指针的声明:
int *pt
另一种指针的声明:
int* pt
推荐使用第一种声明方式,这样易读,读起来就是,定义一个指针,这个指针指向int类型的值



4指针赋值和引用赋值的区别
指针赋值:
int ival = 1024, ival2 = 2048;
int *pi = &ival, *pi2 = &ival2;
pi = pi2; // pi now points to ival2  指针指的位置变了,指针指的对象的内容没有变
引用赋值:
int &ri = ival, &ri2 = ival2;
ri = ri2; // assigns ival2 to ival 引用没有变,引用的内容变了
(ps:引用的初始化是一次性的)

const double *cptr; // cptr may point to a double that is const指向一个const的double变量
允许把非 const 对象的地址赋给指向 const 对象的指针
既可以把const类型的也可以吧非const类型的对象赋值给const指针,均不能使用这个指针来修改这些变量的值
可以把指向 const 的指针理解为“自以为指向 const 的 
指针”

C++ 语言还提供了 const 指针——本身的值  
不能修改(指针中包含的地址不能修改)
int *const curErr = &errNumb; // curErr is a constant pointer

typedef string *pstring;
const pstring cstr;
后面这一句的等价于:
string *const cstr; // equivalent to const pstring cstr

针对上面这个问题的一个总结:
string s;
typedef string *pstring;
const pstring cstr1 = &s; // written this way the type  is obscured 
pstring const cstr2 = &s; // all three decreations are  the same type 
string *const cstr3 = &s; // they're all const pointers  to string
上面这三种方式都是一样的,表示一个const指针,这个指针指向string类型(第三种写法最清晰)


5 符号的结合性
移位操作符有左结合性,赋值操作符有右结合性
算术操作符左结合,比较操作符右结合

6 多用前置的++
只有在必要时才使用后置操作符(i++),因为这种情况需要先保留原值。

由于后自增操作的优先级高于解引用操作,因此 *iter++ 等效于 *(iter++)。子表达式 iter++ 使 iter 加 1,然后返回 iter 原值的副本作为 
该表达式的结果。因此,解引用操作 * 的操作数是 iter 未加 1 前的副本


7点操作符和箭头操作符
点操作符用于获取类类型对象的成员

假设有一 个指向类类型对象的指针(或迭代器),下面的表达式相互等价:
(*p).foo; // dereference p to get an object and fetch its member named foo 
p->foo; // equivalent way to fetch the foo from the object to which p points


8 new创建
1. new() 分配这种类型的一个大小的内存空间,并以括号中的值来初始化这个变量;  . U* t, v# ~% u
2. new[] 分配这种类型的n个大小的内存空间,并用默认构造函数来初始化这些变量;



9 三种内存管理容易出现的毛病
经常出现的三种内存管理的错误:
1 回收动态分配的内存失败
2读写已删除的对象
3对同一个内存空间进行两次delete



10 类型转换

什么时候发生隐式的类型转换
1 在混合类型的表达式中,操作数都变为相同类型
2 做条件表达式总,被转换为bool类型
3赋值或初始化的时候(用一表达式初始化某个变量,或将一表达式赋值给某个变量,则该表达式 被转换为该变量的类型

算术装换
有符号和无符号之间的装换(依赖于机器)

四种强制装换
1  dynamic_cast :支持运行时识别指针或引用所指向的对象
2 const_cast :将转换掉表达式的 const 性质
3 static_cast: 编译器隐式执行的任何类型转换都可以由 static_cast 显式完成
4 reinterpret_cast:  通常为操作数的位模式提供较低层次的重新解释

命名的强制类型转换符号的一般形式如下:
cast-name<type>(expression);




11 if_else 匹配

关于if~else匹配   通过将 else 匹配给最后出现的尚未匹配的 if  


12 异常处理
异常处理:
try
throw:throw 表达式的 类型决定了所抛出异常的类型。
catch
每个 catch 子句包括三部分:关键字 catch,圆 括号内单个类型或者单个对象的声明——称为异常说明符,以及通常用花括号括 起来的语句块。如果选择了一个 catch 子句来处理异常,则执行相关的块语句。 一旦 catch 子句执行结束,程序流程立即继续执行紧随着最后一个 catch 子句的句。
标准库里面的异常类,用来传递错误信息


13 const
const对象,指向const对象的指针或者引用只能用于调用其const成员函数,如果尝试用它们来调用非const成员函数,则是错误的。

仅当形参是引用或指针时,形参是否为const才有影响,不能基于指针本身是否为const来实现函数的重载。(要是指针指向的是否是const)
所以形参应用 是const* 才能重载
*const就不能利用const来重载
如果使用引用形参的唯一目的就是避免复制实参,则应将形参定义为const引用

不需要修改的引用参数定义为const引用,普通的非const引用形参在使用时不太灵活,这样的形参既不能使用const对象初始化,也不能用字面值或者产生右值的表达式初始化。


14 关于数组作为参数
非引用类型的数组形参,就是转换为指向数组的指针,数组长度被忽略
引用类型的数组形参,为数组的传递,数组长度有效


15 STL
容器元素必须满足下面两种约束:
1 元类型必须支持赋值运算
2 元素类型对象必须可以复制
所以引用类型不可以,引用不支持一般意义上的赋值,当然IO也不行

vector和deque容器的迭代器提供额外的运算,比如所>,<等比较

不要存储end操作返回的迭代器,添加或者删除deque或vector容器内的元素都会导致存储的迭代器失效。

{}表示一个集合
<>一般内括类型
()一般表示内容


对于map  value_type并非元素类型,而是pair类型

在迭代遍历关联容器时,我们确保按键的顺序访问元素,而与元素在容器中存放的位置完全无关。
关联的本质在于元素的值与某个特定的键相关联,而并非通过元素在数组中的位置来存取。


multimap不支持下标运算

泛型算法基于迭代器及其操作实现,而并非基于容器操作(使用普通迭代器时,算法从不修改基础容器的大小

算法不直接修改容器大小,如果需要添加或删除元素,则必须使用容器操作
谓词就是做某些检测的函数,返回用于条件判断的类型,指出条件是否成立
容器的方法和算法的方法有区别哦。举例:容器的insert 和算法中的insert有区别


算法中函数的命名方法:

函数后带if则表示这个函数使用谓词
函数带copy则表示结果存储在另外一个容器中。




_______________________________________________________________无聊的 分割

面向对象
类背后蕴藏的基本思想是数据抽象和封装

在类内部定义的成员函数,将自动作为inline处理,也就是说,当他们被调用的时候,编译器将试图在同一行内扩展该函数,也可以显示的 将成员函数声明为inline


1 类作用域中名字的查找

 函数内——函数外类内部——类外函数定义之前


2构造函数中的初始化式
>>>构造函数初始化式只在构造函数中定义而不是声明中指定
构造函数分两个阶段执行
first: 初始化阶段,指的是“()”初始化列表中初始化
second: 计算阶段,“{ }”,有构造函数体中的所有语句组成
在第二种方式中,是先隐式的使用默认的构造函数来初始化,最后在{}中覆盖····

必须对任何const或者引用类型成员以及没有默认构造函数的类类型的任何成员使用初始化式

3 static ;const; const static三种成员的初始化
class Test  
{  
public:  
      Test():a(0){}  
      enum {size1=100,size2=200};  
private:  
      const int a;//只能在构造函数初始化列表中初始化   
       static int b;//在类的实现文件中定义并初始化   
      const static int c;//与 static const int c;相同。   
};  
  
int Test::b=0;//static成员变量不能在构造函数初始化列表中初始化,因为它不属于某个对象。   
cosnt int Test::c=0;//注意:给静态成员变量赋值时,不需要加static修饰符。但要加cosnt  
PS:static函数成员没有this指针,它属于类,不属于这个类的对象


4 explicit关键字
用来防止隐式类型转化














原文地址:https://www.cnblogs.com/riasky/p/3430930.html