语法糖(Syntactic sugar)是由Peter J. Landin(和图灵一样的天才人物,是他最先发现了Lambda演算,由此而创立了函数式编程)创造的一个词语,它意指那些没有给计算机语言添加新功能,而只是对人类来说更“甜蜜”的语法。语法糖往往给程序员提供了更实用的编码方式,有益于更好的编码风格,更易读。不过其并没有给语言添加什么新东西。
假设解决某一问题有两个写法A,B,其中A使用较简单的语法,需要写较多的代码;B使用较抽象的语法,只需要写较少的代码。B使用的语法是对A使用的语法的抽象,称为语法糖,其中的对应关系由编译器来实现。
所以说,在C等许多语言中都有许多习惯用法其实都是语法糖。
语法糖可以提供方便,让程序员少写几行代码,让代码看起来简洁。不过有时语法糖不如多个语句组合灵活。
#include
int main()
{
int a =1;
int *p =&a;
printf("%d
",0[p]); // 1
int b[1] = {3};
int *q = b;
printf("%d
",0[q]); // 3
return 0;
} 这说明什么呢?在《征服C指针》一书中提到,表达式中的[ ]其实就是语法糖,也就是说对于一个指向某种类型的指针p,一个整数n而言:p[n]=[n]p=*(p+n) ,即指针p所指向的内存地址+sizeof(*p*n)之后的地址。
实际上,lambda不是函数(这是它们如何避免C++不支持嵌套函数的限制的一部分)。它们是一种特殊的对象,叫做仿函数(functor)。functor是包含重载操作符()的对象,重载操作符使它们像函数一样可调用。
当编译器遇到lambda定义时,它会为lambda创建一个自定义对象定义(custom object definition)。每个捕获的变量都成为对象的数据成员。
在运行时,当遇到lambda定义时,将实例化lambda对象,并在此时初始化lambda的成员。
for循环是while循环的语法糖,while循环是跳转指令的语法糖。
int i = 0;
while(i这里for循环的优点是循环控制变量的初始化和更新都集中到了一起,能防止自增语句忘了写,do()部分长一点的话往往被忽略。不过有些情况使用其它循环写法更易读:
while(iter!=list.end)
{
if(cond(iter))
iter=list.delete(iter); //删除list中符合条件的元素
else
++iter;
}基于范围的for语句是普通for的语法糖。
for(declaration: expression)
statementexpression是一个对象,表示一个序列;
declaration部分定义一个变量,被用于访问序列中的基础元素,每次迭代该变量会被初始化为expression的下一个元素值。
如:
vector v = {0, 1, 2, 3, 4, 5};
for(auto &r: v)
r *= 2; 使用自增的优点是大大减少了代码量,有时会代码更精简,有时更易读。但有时也会令人费解,降低代码的可读性。特别是后置自增自减语句,理解起来一定要将其做为两句来理解。
n = *p++;
// 要理解为:
n = *p;
p++;demo code:
//减少代码量的例子
while((*des++ = *src++) != 0);
//可以用下面的代替
while((*des = *src) != 0)
{
++des;
++src;
}
//下面这个代码就没办法缩成一行,把自增放到上面会有未定义行为
while(des[i] = src[i]) // 同一个表达式不能在多处对同一变量产生副作用
++i;当变量名较长时,如果不使用复合赋值运算符,当这一变量是对自身取值并更新时,变量名要写两次,费事且有时会容易写错。早期编译器如果不使用复合赋值运算符,还有临时对象一说。
面向对象的代码最终会翻译成面向过程的代码形式,其实这也是一种分层抽象的方式(当然,你也可以理解为高级编程语言是机器语言的抽象,指令集是CPU的抽象)。
#include
using namespace std;
// 角色c1 圆接口定义者,可放到头文件,使用文件来区分模块
struct CCircle{
double radius;
};
double area(struct CCircle cc);
// 角色c2 圆接口实现者,可以放到实现文件
double area(struct CCircle cc){
return cc.radius * cc.radius * 3.14159;
}
// 角色c3 圆接口使用者,可以放到使用文件
void calc()
{
struct CCircle cc;
cc.radius = 10;
double a = area(cc);
printf("circle's area is %lf
", a);
}
// 角色cpp1 圆接口定义者,可放到头文件,使用文件和类来区分模块
class CppCircle{
public:
double radius;
double area();
};
// 角色cpp2 圆接口实现者,可以放到实现文件
double CppCircle::area(){
return radius * radius * 3.14159;
}
// 角色cpp3 圆接口使用者,可以放到使用文件
void calc2()
{
CppCircle cc;
cc.radius = 10;
double a = cc.area();
printf("circle's area is %lf
", a);
}
int main()
{
calc();
calc2();
getchar();
return 0;
} 7.1 typedef
7.2 using
using SI = Sales_item; //SI是Sales_item的别名声明,
// 把等号左侧的名字规定成等号右侧类型的别名7.3 using可以起模板别名.
auto让编译器通过初始值来推算变量类型。
auto i = 0, *p = &i; // ok
auto sz = 0, pi = 3.14; // error, 类型不统一auto一般会忽略顶层const,保留底层const(修饰指针或引用的const)。如果希望保留顶层const,要明确指出
const auto p = ci;设置类型为auto的引用时,初始值中的顶层const属性保留。
int const * const p; // 底层 * 顶层:类型指示符,顶层const能被保留。
decltype((i)) d; // error, 对表达式套括号的结果永远是引用,
// 不套括号则仅当i是引用时,才是引用。-End-
| 留言与评论(共有 0 条评论) “” |