C++ Primer(表达式)

来源:互联网 发布:淘宝充话费怎么代理 编辑:程序博客网 时间:2024/05/13 14:24

1.算术操作符

整除(/)与求余(%)运算

21%-5;  //result is 1 or -4

21/-5;    //result is -4 or -5

2.关系操作符和逻辑操作符

逻辑与和逻辑或总是先计算左操作数,再计算右操作数。

if(i<j<k)   //第一个小于操作的结果是true或false,也就是k与整数0或1做比较。

if(val==1)  //当val等于指定的1值是,条件才成立

if(val)    //val为任意非零值,条件判断都成立

char *cp="hello world";

while(cp&&*cp);   //指针cp为非空指针且cp指向的字符为非空

3.位操作符

位异或操作符(^):两个操作符对应的位只有一个(不是两个)1,则操作结果中该位为1,否则为0。

bitset优于整数数据的低级直接位操作

bitset<30> bitset_quiz1;

unsigned long int_quiz1=0;

bitset_quiz1.set(27);    //27位置1

int_quiz1 |= 1UL << 27;   //27位置1

bitset_quiz1.reset(27);    //27位置0

int_quiz1 &= ~(1UL << 27);   //27位置0

 bool status;

status=bitset_quiz1[27];   //查看27位结果

stastu=int_quiz1&(1UL<<27);//查看27位结果

移位运算符具有中等优先级:比算术操作符低,比关系操作符、赋值操作符和条件操作符高。

<<优先级高于<,所以

 cout << (10 < 32); // ok,输出1

cout << 10 < 32;   // error,将10写到cout,然后用此操作(cout)的结果与32比较

4.赋值操作符

赋值操作符的左操作数必须是非const的左值。数组名是不可修改的左值,因此数组不可用作赋值操作符的目标。下标和引用操作符都返回左值,用于非const数组时,可作为赋值操作的左操作数。

int ia[10];

ia[0]=0;

*ia=0;

赋值操作符具有低优先级

int i;

while((i=get_value())!=42){

  //do something

}

5.自增和自减操作符

int i=0,j;

j=++i;   //j=1,i=1

j=i++;   //j=1,i=2

前置操作只需加1后返回加1后的结果即可。而后置操作符则必须先保存原来的值,以便返回未加1之前的值作为操作的结果。对于复杂的迭代器类型,话费更大的代价。尽量使用前置操作。

*iter==等效于*(iter++)

6.箭头操作符

Sales_item *sp=&item1;

(*sp).same_isbn(item2);

等效于

sp->same_isbn(item2);

7.sizeof操作符

sizeof (expr)

sizeof (type name) // 必须加括号

sizeof expr :  并没有计算表达式的值


Sales_item item, *p;

sizeof item;

sizeof *p; // 并没有解引用操作,  p指向一块没有意义的地址

sizeof (Sales_item)

8.处理复合表达式

  1. 有怀疑则在表达式上按程序逻辑要求使用圆括号强制操作数的组合
  2. 修改操作数的值不要在同一个语句的其他地方使用该操作数。

if (ia[index++]<ia[index]);  //此表达式没有明确定义

if(ia[index]<ia[index+1]);  //明确定义

9.new和delete表达式

int *p = new int; //ok 没有初始化

int *p = new int();// okp所指的对象内容初始化为0


int *p = 0;

delete p; // ok,可以删除空指针

delete p;之后,删掉了它所指向的对象,p此时成了悬挂指针,应该p = 0;


如果你使用delete是未加括号,delete便假设删除对象是单一对象。否则便假设删除对象是个数组。delete[] 相比 delete 会多做一件事,就是在删除这个内存块前,析构每个元素,特别是对于对象数组。需要重载 new, delete,new[], delete[], 我们必须全部都重载,而不能仅仅重载 new, delete, 然后希望 new[],delete[] 会调用它们。

string*Ptr1 = new string;

string *Ptr2 = newstring[100];
……
delete Ptr1;
delete [] Ptr2;

 动态创建const对象:

const int *pci = new const int(32); // 定义的时候必须初始化,初始化后就不可以修改 pci指向一个const对象,所以它也要是const

1)  普通指针不能指向const对象;

void reset(int *pi) //实参不能是指向const int对象的指针

 // 为了保护所指向的值,一般地将定义为指向const对象的指针

void reset(const int *cpi);

2)  指向const对象的指针可以用普通指针来初始化

3)  指向const对象的指针可以指向非const对象,但不能修改它,可以赋给非指向const对象的指针来改;

4)  可以使用普通指针初始化const指针

5)  不能用const对象来初始化非const的引用

6)  可以使用const对象来初始化非const对象,反之亦然

所以const形参的时候,实参可以是const对象也可以是非const对象

const string *pcs = new conststring; // ok

内置类型的以及没有默认构造函数的类型必须显式初始化


可以删除const指针:

delete pcs; // ok

10.类型转换

char, signed char, unsigned char, short, unsignedshort如果能包容在int内则转换为int,否则转成unsigned int(主要针对unsiged short),bool 提升为int, false转为0, true转为1

    inta = 2 + true;

    cout<< a << endl; // 3

向上提升:int->unsigned int->long->unsignedlong

signed int + unsigned int,则signed int会转为unsigned int

unsignedchar b = -1; // 1000 0001,符号位不变所有位取反,再加1 : 1111 1111

cout<< (int)b << endl; // 255

int i = 32;

constint &iref = i; // 使用非const对象初始化const对象的引用,将非const对象转成const对象

i= 33;

//iref= 34; // error

cout<< iref << endl; //ok, iref要随着i而变 = 33

const int *cpi = &i; // 非const对象的地址(或非const指针)转成指向相关const类型的指针

int *pi = &i;

const int *cpi2 = pi; // 可以使用非const指针初始化const指针

11.显式转换

1)cast-name<type>(expression)

dynamic_cast 运行时识别指针或引用所指向的对象

2)const_cast  转换掉表达式的const性质

 const int ci = 32;

 int ival = const_cast<int>(ci);//error不能从const intint

 int *iref2 = const_cast<int*>(ci); // 可以将const转换掉

3)static_cast编译器隐式执行的任何类型转换都可以由static_cast显式完成。

double d=97.0;char ch=static_cast<char>(d);

4)reinterpret_cast

为操作数的位模式提供较低层次的重新解释,依赖于机器,要阅读编译器细节。

int *ip;

char *pc = reinterpret_cast<char*>(ip);//不能把pc看成是普通字符指针,程序员必须记住pc指向真正指向的是int

string str(pc); // compile error

6)   在新编译器上写程序,最好不要用()式的老强制转换


0 0