C++ Primer第四章!
#include "stdafx.h"
#include<iostream>
#include<string>
#include<vector>
#include<typeinfo>
using namespace std;
int main()
{
//逻辑与(&&)、逻辑或(||),条件(?:),逗号(,)规定了运算对象求值顺序,先求左侧运算对象!
//拿不准的时候用括号表达式强制更改组合关系;如果改变了某个运算对象的值,在表达式其他地方就不要再使用这个运算对象。
//算术运算符(+、-、*、/、%、+、-),算术表达式有可能产生未定义结果,一是数学性质原因(如除数为0),二是计算机原因(如结果溢出)
//运算符%,取余运算符,负责计算两个整数相除所得的余数!
int ival1 = 42;
double dval1 = 3.14;
int ival2 = ival1 % 12; //算术表达式的求值结果都是右值
//int ival3 = ival1%dval1; 错误行为!
//(-m)/n和m/(-n)都等于-(m/n);m%(-n)等于m%n、(-m)%n等于-(m%n)
//关系运算符用于算术类型和指针类型,逻辑运算符用于任意能转换为布尔值类型,返回值都为布尔类型!
//逻辑与、逻辑或具有短路求值策略,当且仅当左侧运算对象无法确定表达式的结果时才会计算右侧对象的值!
vector<string> text = { "abcdefg" ,"hijklmn"};
for (const auto &s : text)
{
cout << s;
if (s.empty() || s[s.size() - 1] == '.') //短路求值策略,只有当S非空时才会用下标运算符去访问它,避免bug!
cout << endl;
else
cout << " ";
}
//进行比较运算时,除非比较对象是布尔类型,否则不要使用布尔面值true作为运算对象!
//if(ival1==true) 不推荐这样使用,而推荐if(ival1)!
//赋值不是初始化,赋值运算符左侧必须是一个可修改的左值。赋值运算符满足右结合律。
int ival3, ival4,*pval;
ival3 = ival4 = 0; //正确:都被赋值为0
//ival3=pval=0 错误,不能把指针的值赋给int
//递增递减运算符,建议使用前置版本的元素符
int i = 0, j;
j = ++i; //j=1,i=1前置版本得到递增之后的值
cout << i << j<<endl;
j = i++; //j=1,i=2后置版本得到递增之前的值
cout << i << j<<endl;
//*p++等价于*(p++),即先解引用,再p++。等价于{*p;p++}
string s1 = "abcdefg";
auto beg = s1.begin();
while (beg != s1.end() && !isspace(*beg))
{
//*beg=toupper(*beg++) 错误:右侧的运算对象改变了beg的值!等价于*(p+1)=toupper(*p)
break;
}
//箭头运算符,返回一个左值,ptr->mem等价于(*ptr).mem
string s2 = "a string", *p = &s1;
auto n = s1.size();
n = p->size();
n = (*p).size();
//条件运算符
int grade = 90;
string finalgrade = (grade > 90) ? "high pass" : (grade < 60) ? "fail" : "pass"; //条件运算最好不要嵌套超过2层,代码可读性不好
cout << ((grade>=60) ? "pass" : "fail");
//位运算符,作用于整型类型的运算
//c++标准库类型有bitset,位运算符同样能够用于bieset类。建议将位运算符仅用于处理无符号类型!
unsigned char bits = 0233;
bits<< 8; //无符号char提升为int,左移运算符<<在右侧插补0,右移运算符在左侧插补0(具体视环境而定)
bits >>3;
~bits; //1置为0,0置为1
unsigned char b1 = 0145, b2 = 0257;
bits = b1&b2; //(&/|/^),与都为1则为1,或有1则为1,异或有且只有一个1则为1
//sizeof运算符,返回一个表达式或者类型所占的字节数(返回值为常量表达式constexpr)
cout << sizeof(*p) << endl; //sizeof不需要真的解引用指针也能知道他所指对象的类型,即大小。
//逗号运算符,含有2个运算对象,从左到右顺序依次求值!
for (int i = 0, j = 0; i < 3; ++i, ++j)
cout << j << "-";
cout << endl;
//类型转换
int ival7 = 3.14 + 3; //3转为double型,double转为int
//比int类型小的整型提升为较大的整型!long吗?
//在条件中,非布尔值转为布尔类型!同时自定义类类型推荐定义向布尔转换的类型转换函数!
//初始化中,右侧运算对象转为左侧对象类型!
//函数调用时也会发生类型转换!
//隐式类型转换
int arry_a[10];
int *p_arry = arry_a; //ia转换成指向数组首元素的指针
//常量整数值0或者字面值nullptr能转换成任意指针类型;指向任意非常量的指针能转换成void*;指向任意对象的指针能转换成const void*;
//显示转换,转换的本质非常危险!
//命名的强制类型转换,static_cast/dynamic_cast/const_cast/reinterpret_cast
int i_cast = 1, j_cast = 2;
double slope = static_cast<double>(j) / i; //当转换时发生精度损失,使用强制转换时不会发生警告信息
void *p_cast = &slope;
double *pp_cast = static_cast<double*>(p_cast);
//改变运算对象底层const
const char *pc=" ";
char *pc_cast = const_cast<char*>(pc); //去掉常量属性
//reinterpret_cast,为对象的模式提供较低层次上的重新解释
int i_decltype,*pi_decltype; //#include<typeinfo>,typeid(p_decltype).name() 返回变量的类型
decltype(i_decltype) p_decltype; //int
decltype(*pi_decltype) pp_decltype=i_decltype; //int&
decltype(&pi_decltype) ppp_decltype=&pi_decltype; //int**
decltype((i_decltype)) pppp_decltype=i_decltype; //int&
cout << typeid(p_decltype).name() << endl;
cout << typeid(pp_decltype).name() << endl;
cout << typeid(ppp_decltype).name() << endl;
cout << typeid(pppp_decltype).name() << endl;
cin.ignore();
return 0;
}
//左值可以位于赋值语句的左侧,而右值则不能。当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)
//int p;则decltype(p)返回的结果为int&,而decltype(&p)返回的结果为int**。
//P147页罗列了全部运算符,同一组优先级相同,组别越靠前优先级越高!
//主要介绍了C++的内置运算符,以及其优先律和结合律。接着简述了表达式中类型的相互转换原则,隐式转换和显示转换。