C++

C++一些有意思的语法

  • { }、( )列表初始化来初始化变量/对象(初始化和赋值有区别)
  • while condition内写自增或自减运算符[while(i++>N)]C++程序员在写自增的时候总是爱写++i(?)
  • 逗号运算符(),如用于for语句中for(;;++i,–j)
  • ? :条件运算符;
  • while(cin>>val)和if(cin>>val),实现未知数量的输入;
  • 变量声明和定义分隔的分离式编译机制(extern关键字);
  • 对指针的引用(指针引用*&),注意没有指向引用的指针,因为引用不是一个对象,但指针是一个对象;
  • 类型别名typedef和别名声明using,注意用类型别名后const指针的层级发生了变化;
  • 基于范围的for语句,for ( declaration : expression) statement;,如for ( auto c : str_name);
  • C++可以通过引用形参返回额外信息,以解决return函数只能返回一个变量值的局限,也可以使用返回值是{ }花括号括住的列表来初始化函数返回的临时量,而使用initializer_list标准库可以实现可变数量但类型相同的形参列表
  • 可以通过构造函数初始值列表的方法,即构造函数名后冒号用[成员变量(初始值)]列表的方法来进行类内初始化,不要忘记初始值后面是构造函数体{ },当你需要默认构造函数时,用=default来增加默认构造函数;

C++一些要注意的语法

  • 常量引用const int/… &、指向常量的指针和常量指针(区别开引用不是对象但指针是对象)constexpr常量表达式与constexpr指针,常量表达式constexpr可以用来帮助将某个非常量表达式转化为常量表达式以符合常量要求,如数组声明时要求常量作为数组长度
  • auto类型及与顶/底层const(引用、指针、一般变量)的关系,decltype类型与const、引用关系auto和decltype常常用于迭代某一容器或对象的元素时
  • 头文件保护符防止重复包含;
  • 对象的直接初始化(除=外如{ }、( )初始化方式)和拷贝初始化(=),建议用直接初始化的方式,类内初始化不能用( ),列表初始化只能用{ }=赋值(可认为拷贝了副本);
  • C++为了兼容C程序,其字符串字面值不是string类型的,也就是用+号操作两个字符串变量时,其中一个必须是string类型的C++包含C语言标准库时最好用cname.h来标识该库是继承自C语言的标准库
  • 当你想要改变传入参数(实参)的值时,可以用传引用或指针的方式,因为引用是起了一个别名,所以对引用的操作都会影响到原对象;
  • vector初始化时,用{ }表示列表初始化,用( )表示vector定义的长度
  • string::size_type和vector<int>::size_type类型,一般是适合于所运行机器的无符号整数,要注意它与其它数如int型变量的比较
  • vector在用下标访问超出vector长度的元素时,编译器并不会报错,而是返回一个不可预知的值,产生缓冲区溢出错误,要注意
  • 迭代器类型iterator和const_iterator,和指针类型相似,但和size_type一样,具体的类型由机器所决定,一般用auto声明,可以被解引用,类似于size_type的还有difference_type(两个迭代器相减)、ptrdiff_t(两个指针相减)类型;
  • ->箭头运算符实际上是解引用运算符(*)和成员访问运算符(.)的结合体;
  • 数组声明一般不允许拷贝初始化,也不允许数组赋值(=),数组的复杂声明,如int *(&ptr)[10],要从内往外读,该语句定义了一个对含有10个元素的指针数组的引用,数组的下标常被定义为与机器相关的无符号数类型;
  • 指针和数组,很多用到数组名的地方,编译器会自动将其替换为一个指向数组首地址的指针,string *p=num_array;等价于string *p=&num_array[0];,另外需注意用auto和decltype推断类型来创建新数组时创建的类型不一样,auto会创建指针类型,而decltype会创建数组类型,数组的下标类型和vector、string类型都不同,数组下标可以为负值,而vector、string类型下标应为一无符号数;
  • begin和end函数(对于数组)、begin和end成员函数(对于容器),迭代器类型,指针作为数组的迭代器
  • C风格的字符串与C++不同,strlen和<、>比较运算以及+运算要注意,前者是因为strlen要一直找到字符串结束符才停止计算,后者是因为在C风格中对数组操作实际上是对其指针操作,C++字符串类可以与C中字符数组混用,但在用C++的string类初始化C的字符数组时,需要用c_str成员函数;
  • 可以用数组来初始化vector(用首地址和尾后地址),但不可以用vector来初始化数组
  • 使用for范围语句来处理多维数组时,要注意外层变量要用引用,否则由于变量是一个数组类型会被判定为指针,可以用类型别名typedef和using来简化多维数组的指针,范围for语句要遍历的是一个序列,这些序列的共同点是能拥有能返回迭代器的begin和end成员
for(auto &row:ia)    //正确,row是引用
	for(auto col:row)
		/*语句*/

for(auto row:ia)    //错误,由于row是一个数组,因此row会被定义为指针类型,且row指针会指向内层数组的首地址,类似于begin和end函数
	for(auto col:row)
		/*语句*/
  • C++中的左值和右值,可以理解为当一个对象被用作右值时,用的是它的值(内容),而当它被用作左值时,用的是它的身份(在内存中的位置),左值右值要分清;
  • 注意运算符对求值顺序的规定,如cout<<i<<" "<<++i<<endl;中<<运算符对++求值顺序没有规定,因此它得到的值是不可预知的,所以涉及到求值顺序、优先级和结合律的表达式,要注意它的计算过程
  • 一元运算符如+、-作用于一个指针或者算术运算值时,返回运算对象值的一个(提升后的)副本,即小整数类型(如bool、char、short等)往往会被提升为较大的整数类型,通常是int
  • 位运算符,使用位运算符~、<<、>>、&、^、|时,要注意一般都是对无符号数操作,因为这些运算符对符号的操作是未定义的,而且这些运算符会将"小整型"提升成较大的整数类型,且移位运算符/IO运算符比算术运算符优先级低,但比关系运算符、赋值运算符和条件运算符优先级高,要注意;
  • 算术转换和整型提升,算术转换是在一个表达式里将运算对象转换成其中最宽的数据类型,整型提升是对于bool、char、signed char、unsigned char、short和unsigned short等类型来说,只要它们的提升后可以存在int里就转换为int类型,否则提升为unsigned int类型里,其它隐式转换,如数组名自动转换为指针、指针转换、布尔类型转换、常量、类类型定义转换;
  • 显式类型转换,cast-name(expression),其中cast-name包括static_cast、dynamic_cast、const_cast和reinterpret_cast
  • 悬垂else,C++规定else和它最接近的if匹配,不要被缩进淆,最好用{ }来规定执行路径
  • 注意switch语句当一个case满足条件后,其后所有case语句的statement都会执行,所以最好每一个case语句都加一个break,而且最好写一个default,当你需要在switch语句内定义变量时,要注意变量作用域
  • try…throw…catch语句,注意要在try和catch后的语句加上{ },而且try和catch后没有冒号,注意多try语句情况下异常与catch的匹配关系,exception、bad_alloc、bad_cast对象只能默认初始化,而其它异常类型正好相反,只允许有初始值
  • C++支持分离式编译,最好将声明(变量、函数)写在一个头文件中
  • 就像引用初始化的规则一样,不允许将const对象、字面值和需要类型转换的对象传递给普通的引用形参,但允许将字面值、const对象传递给常量引用形参
  • 数组形参,数组在传递时实际上传递的是指向该数组的首地址,因此数组的形参可以写为const int *或const int [ ]或者const int [10],在传入数组时,因为事先不知道数组长度,所以有常用的三种管理数组指针形参的方式,传递多维数组时,实际上是传递的一个数组指针,所以形参应写为int matrix[ ] [10]或int (*matrix)[10]之类;
  • 不要用return返回一个局部作用域的指针,当函数调用完之后,局部作用域内所有变量都会被销毁,包括局部作用域内的指针
  • 想要将数组指针作为返回类型时,有四种方式,分别是直接写、用类型别名简化返回类型说明、用尾置返回类型和使用decltype
  • 重载和const形参:只有当形参是常引用变量(const Account&)或者指向常量的指针(const Account*)时,const才有用,也就是区别于(Account&)和(Account*)的形式,其它地方const与(Account&)和(Account*)是没有区别的,这是由于顶层的const不影响传入函数的对象,而对于传入的非常量实参,可以用const_cast<const string&>的方式来保证安全;函数重载时局部作用域内部的函数会使得局部作用域外部的函数被隐藏,外部的同名函数不再起作用;与之相反,局部变量不能作为默认实参,但是可以在局部作用域内为全局变量赋值后再调用函数时默认实参会以新的值传入;
  • 用函数返回值给常量表达式类型的变量初始化时函数必须是constexpr常量表达式类型,因为constexpr修饰的常量表达式变量是在编译期间就确定的常量,而且constexpr和inline修饰的函数定义最好放到头文件中,因为constexpr修饰函数也是一种隐式内联函数,会在"内联点"展开,而展开时必须要能找到函数的定义
  • 使用assert断言预处理宏和NDEBUG预处理变量来帮助调试和关闭断言assert调试
  • 重载函数匹配存在最佳到最劣的几种类型,要注意;
  • 函数指针使用时可以直接将函数名赋值给指针与取地址后赋值给指针是一样的,在调用指针函数时,可以用对指针名的解引用,也可以直接用指针名,函数指针与数组指针一样可以作为另一函数的形参,这时可以用typedef类型别名简化形参描述,而传实参时直接传入函数名时编译器会直接将函数名转换为对应的指针,当然也可以定义指针后传入;同样地,函数返回类型也可以是函数指针,但要注意的是需要将返回类型显式地写成一个指针类型,因为编译器不会将函数返回值类型作为指针类型来处理;
  • IO类无法拷贝,只能通过引用来传递它们
  • 类的拷贝、赋值和析构都需要定义,如果我们不定义它们,那么编译器将会为我们自动定义这些内容,但这些自动定义的有可能出问题;
  • 有些编译器要求友元函数不仅仅需要在类内声明,还需要独立的声明,因此常常将类的声明和友元函数的单独声明写在一个头文件中;
  • 可变数据成员:mutable修饰的数据成员,可变数据成员永远不是const,即使它是const对象的成员,而且任何成员函数,包括const函数,都可以改变它的值C++的常量成员函数,该成员函数不会改变任何成员的值,在成员函数后加const关键字
  • 提供类内初始值时,必须用=的初始化形式或者花括号{ }括起来的直接初始化方式;
  • 返回*this的成员函数,注意声明这个成员函数的返回类型是该类的引用,这样就不会产生该对象的副本,而是对对象本身进行更改;一个类的成员类型不是自己,但一个类的成员类型可以是指向自己类型的指针或引用;
  • 友元类:友元类的成员函数可以访问另一个类中的所有成员;友元成员函数,A类的成员可以被B类的友元成员函数访问,而且要注意声明和定义的要求,先定义B类,再定义A类,再定义友元成员函数;重载函数时每一个重载函数都要声明为友元函数;友元函数(外部)声明先于使用;
  • 类作用域,如果想要使用类外的某个变量,可以(但不一定必要)在前面加上全局作用域标识::来指示;
  • 尽量避免用类成员来初始化另一个成员,因为初始化时顺序是按照类的成员定义顺序来初始化的,而不是根据构造函数的初始化列表的顺序初始化的;
  • C++中允许有委托构造函数(delegating constructor),用于扩展初始化,一个委托构造函数利用其它构造函数执行了自己的初始化过程,若一个构造函数为所有参数提供了默认实参,那么它实际上就定义了一个默认构造函数;
  • 隐式类类型转换,但是编译器每次只允许一次隐式类类型转换,如传入某函数的实参类类型与声明的形参类类型可以由一次隐式类类型转换完成,可以用在构造函数声明前加explicit来阻止隐式类类型转换的发生,并且带有explicit声明构造函数的类所实例化的对象只能用直接初始化的方式初始化,不能用拷贝初始化的方式进行初始化(=);可以通过显式声明的方式来进行类类型转换;
  • 聚合类,类似于C语言中的结构体类型;字面值常量类和constexpr构造函数;
  • 类的静态成员static,静态成员是属于该类的,但不属于其中实例化的任何一个对象。访问:由类名访问,仍可用对象成员访问运算符访问;类静态成员定义;类静态成员初始化:通常用类外初始化,但可以用const类型的数据来进行类内初始化,而且必须要求静态成员必须是字面值常量类型的constexpr类型;
  • C中的size_t类型和C++中size_type类型,实际上C++中也有size_type类型,size_type是一种容器类型,表示容器元素的长度,可以保证在程序运行的机器上一个无符号的足够大的数据类型,确保程序在该机器上可以正确运行;而size_t是与sizeof有关的由操作系统/架构决定的无符号整型或长整型;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值