《C++ Primer》读书笔记 第二章

1.在算数表达式中最好不要使用char或bool,只有在存放字符或布尔值时才使用他们,因为char在有些机器上是有符号的,在一些机器上是无符号的,所以特别容易出问题,如果只表示一个不大的整数,那么明确他的类型是signed char或是unsigned char。

2.关于相互赋值。如果按如下定义bool a = 10; int b = a; 那么b = 1,因为bool变量true类型算术运算时会被当成1,false为0。

当我们把一个浮点数赋给一个整数时,会截尾处理。

当把一个非0的书赋给bool变量是,值为true,否则是false。

当把整数赋给浮点数时,若超过浮点数的精确表示范围,会有精度损失,double能表示的精确范围是2的50+次方以内,若大于这个范围的数赋给一个double数,就会有精度损失。

当赋给无符号类型一个超出他表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。例如给unsigned char类型的对象赋值的结果是((x % 256) + 256) % 256, 比如输入-1时值为255.

当赋给带符号类型一个超出他表示范围的值时,结果是未定义的,此时,程序可能继续工作,可能崩溃,也可能产生垃圾数据。

其中无符号类型的优先级高于带符号类型,当一个无符号类型和一个带符号类型的变量在一起运算时,带符号类型的数会转成无符号类型再运算,例如unsigned u= 10; int i = 42;cout << u + i << endl;会输出4294967264,因此不要混用无符号类型和带符号类型。

另外,不能在for语句里这样写 : for (unsigned i = 10; i >= 0; --i) 便是死循环,因为i永远不会小于0。

3.若一个字符串过长可以这样输出 : cout << "abcd"

"efgh"

"ijkl"; 而不用加多个 << 运算符。

4.指定字面值的类型 : L'a' 代表wchar_t类型, u8“hi!” 代表utf-8字符串 42ULL代表unsigned类型1E-3F代表float类型的0.001,3.14L代表long double类型。

u或U代表unsigned, f或F代表float类型,l或L代表long类型或long double类型,ll或LL代表long long类型。

5.普通变量初始化有多种形式:int a = 0; int a = {0}; int a(0); int a{0};其中用花括号初始化是C++11新标准,被称为”列表初始化“,无论初始化还是赋值都可以使用,必须在支持C++11的编译器上才能使用。

不过当使用列表初始化时存在丢失信息的风险时,编译器会报错:double a = 3.14; int b{a}, c={a};都会报错,而int d(a), e = a;都会正确执行。

6.extern是声明一个变量而非定义一个变量,可以在程序其他地方定义这个变量,但是不能给extern声明变量时赋初值,若赋了初值,就会抵消extern的作用,变成定义变量,但这会引发错误。

7.变量命名:用户自定义的变量名中不能连续出现两个下划线,也不能以下划线紧连大写字母开头,此外,定义在函数之外的标识符不能以下划线开头。

8.若在一个变量的作用域内层再定义一个变量,并且在自己的作用域里面覆盖(隐藏)了以前的变量,若外层变量是全局变量,也可调用这个全局变量,方法为::a,因为全局作用域没有名字,所以当操作符左侧为空时,向全局作用域发出请求获取符号右侧名字对应的变量名。

9.引用。引用只是一个已存在对象的别名,但引用不是一个对象,所以不能定义引用的数组,也不能定义引用的引用。

除了两种特殊情况(以后再介绍)外,其他所有类型的引用必须要与绑定的对象类型严格匹配(包括const)。

10.指针。与引用不同的是,指针是一个实实在在存在的对象。因为引用不是对象,所以没有自己的地址,因此不能定义引用的指针,但可以定义指针的引用。

除了两种特殊情况(以后再介绍)外,其他所有类型的指针必须要与指向的对象类型严格匹配(包括const)。

得到空指针最直接的方法就是用nullptr来初始化指针,nullptr是C++11的新内容,可以被转换为任何指针类型,还有两种初始化方法:0和NULL,下面三种写法等价:int *p1 = nullptr; int *p2 = 0; int *p3 = NULL; 不过在新标准下,现在的C++程序最好使用nullptr。

另外,把int变量直接赋值给指针变量是错误的行为,即使int值为0也不行:int zero = 0; int *p = zero//严重错误,切记

建议:初始化所有指针。

11.const类型一经定义无法改变,因此const对象必须初始化。

默认情况下,const对象仅在文件内有效。定义并初始化一个常量,编译器会在编译过程中把用到该变量的地方都替换成对应的值,当多个文件中定义了相同的常量时,其实也就是每个文件中都定义了一个单独的常量。

有时候const变量初始值不是一个常量表达式,但想要在文件间共享,这种情况下,如果不希望编译器生成多个const变量,解决的方法是,对于const变量不管声明还是定义都添加extern关键字,这样只需定义一次就可以了

12.const引用。常量必须被常量引用绑定,不能被变量类型引用绑定,而常量类型的引用也能绑定非常量。

另外,允许一个常量引用绑定一个非常量的对象,字面值,甚至是一般表达式。

double a = 3.14; cons int& b = a;此时b引用了一个int类型的数,对b的操作应该是整数运算,因此,编译器把上述代码变成如下形式: const int temp = a; const int& b = a;因此b绑定了一个临时量。 当b不是常量时,如果int& b = a;不出错的话,那b绑定了一个临时对象,有因为b不是const,因此可以改变绑定对象的值,但我们绑定的是临时量,而不是我们想要的量,因此,这是毫无意义的,C++也不允许这样定义。

当一个常量引用绑定一个变量时,不能用该引用修改该值,但该变量还是变量,可以改变他的值,只不过不能通过这个引用修改罢了。

13.const指针。某些地方和const引用一样,要想存放指向常量的地址,只能用指向常量的指针。

除了两中特殊情况,指针类型也必须与指向的对象类型一致。其中一种是允许指向常量的指针指向非常量的对象。

与const引用类似,指向常量的指针指向非常量对象时,仅仅要求此指针不能改变指向对象的值,但该对象还是可以通过其他方式改变。

14.关于const。const分为顶层const和底层const,指针类型既有顶层const又有底层const,比如:const int* const p; 应从右往左读,右边的const为顶层const,左边的为底层const,对于其他情况,const int a; 则为顶层const;特殊的,用于声明引用的const都是底层const。

当对象之星拷贝操作时,顶层const不受什么影响,例如const int a = 1; int b = a;因此拷入和拷出的对象是否是常量都没什么影响。

但是底层const的限制不能忽视,当执行对象的拷贝操作时,拷入和拷出的对象必须是具有相同的底层const资格,或者两个对象的数据类型必须能够转换,例如非常量可以转换为常量,反之则不行。int a; const int* const p1 = &a; int* p2 = p1;//错误

15.constexpr和常量表达式。常量表达式是指值不会改变而且编译过程中就能确得到的计算结果的表达式,显然,用常量表达式初始化的const对象也是常量表达式。例如:int a = 27;不是常量表达式,因为初始化的不是常量;const int b = 1;是常量表达式;const int c = b + 1;是一个常量表达式。int f(){}  int d = f();不是一个常量表达式;

很多时候很难确定一个初始值是不是一个常量表达式,C++11中规定允许将变量生命为constexpr类型以便编译器来检查验证变量的值是否是一个常量表达式。生命为constexpr的变量一定是一个常量,而且必须用常量表达式来初始化。

int a = 1; constexpr int b = a + 1;//编译器会报错

普通函数虽然不能做为constexpr变量的初始值,但是新标准允许定义一种特殊的constexpr函数,这种函数应该足够简单以使得编译时就可以计算其结果,就能使用constexpr函数来初始化constexpr变量了。

对指针而言,constexpr是顶层const,因此定义时必须初始化,且定义后不能修改,constexpr也可以与底层const同时存在,如constexpr const int* p = nullptr;

16.C++11的using声明新类型。与typedef相似,C++11允许允许为一个类型定义别名,用法:using price = double;表明price和double等价;也可using array = int[10];声明array是一个存放10个整数的数组的类型。

17.关于typedef的特殊之处。例如下面的语句typedef char* pstring; const pstring cstr = 0; const pstring* ps; pstring类型实际上是类型char*的别名,cstr是指向char的常量指针,而不是指向char常量的指针,const pstring cstr = 0;也就相当于char* const cstr = 0 。ps是一个指针,他的对象是指向char的常量指针,而不是指向常量的指针的指针,因此const pstring* ps;也就相当于char* const *ps;。

首先明确pstring是指针类型,因此const pstring是指向char的常量指针类型,而非指向常量字符的指针,此const相当于顶层const而非底层const。

18.auto类型。auto类型可以在不知道对象类型的情况下,让编译器去分析表达式所属的类型,例如auto a = 1 + 2;此时auto代表int。

注意auto分析表达式所属的类型,会去计算表达式的值,这一点要特别注意。另外,auto变量在定义时必须有初始值。

auto也能在一条语句中声明多个变量,但该语句中所有变量的初始基本类型必须一样。

编译器推断出来的auto类型有时候和初始值类型并不一样,编译器会适当的改变结果类型使其更符合初始化规则。

如引用,当引用被用作初始值时,真正参与初始化的其实是引用对象的值,该值的类型用作auto的类型。

其次,auto一般会忽略顶层const,保留底层const。例如const int a = 1; auto b = &a;则b为const int* 类型。如果希望保留顶层const,则应该明确指出:const int a = 1; const auto b = a;

但是auto虽然忽略顶层const,但auto引用(auto&)不会,此时顶层const会变成底层const保留在auto类型中,此时auto应为const T&类型。

19.decltype()函数。功能和auto相似,它的返回值是操作数的数据类型,与auto类型不同的是,编译器分析表达式的类型,但并不去计算表达式的值,切记。

decltype(f()) sum = x; //sum的类型就是f()的返回值类型,编译器并不实际调用函数f(),而是直接使用f()的返回值类型。

decltype处理顶层const和引用的方式与auto有些不同,如果decltype使用的表达式是一个变量,则decltype返回该变量的类型(包括顶层const和引用在内),例如:const int a = 0, &b = a; decltype(b) c = a;则c的类型为const int&类型。

需要指出的是,引用从来都作为气所指对象的同义词出现,只有在decltype处是一个例外。

如果decltype使用的表达式不是一个变量,则decltype返回表达式结果对应的类型,例如int a = 1, &b = a; decltype(b + 1) c;则c是一个int类型的变量。

int a = 1, *p = &a; decltype(*p) b; 则b是一个int&类型的变量,因为解引用操作得到的是对象的类型引用 (解引用返回左值,因为解引用既能返回指针所指对象,又能给这个对象赋值)。

特殊的,对于decltype来说,如果给变量名加上了一对括号,则得到的类型与不加括号时会有不同。如果给变量加上了一层或多层括号,编译器就会把他当成一个表达式。变量是一种可以作为赋值语句左值的特殊表达式,所以这样的decltype就会得到引用类型,比如:int a = 1; decltype((a)) b = a;此时b是int&类型。

切记:decltype((variable))的结果永远是引用,而decltype(variable)的结果只有当variable本身就是一个引用时才是引用。

其他的,赋值是会产生引用的一类典型表达式,引用的类型就是左值的类型,也就是说,如果i是int,则表达式 i = x 的类型是int&。

20.C++11新标准规定,可以为数据成员提供一个类内初始值,C++课本上说旧标准不能在类型直接提供初始值,但我试过了没问题,不知道是什么原因。。。

其他的没提供初始值的给默认初始化,int 为0,string为“”。

21.预处理变量无视C++语言中关于作用域的规则。

转载于:https://www.cnblogs.com/Chierush/p/3450212.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值