今天我们来聊聊C++的类型别名。

如今,定义类型别名有两种定义方法:

    //第一种
    typedef int ZHENGSHU;

这里可以看到,typedef 关键字后面声明了一个 int 类型的别名 ZHENGSHU,在之后的定义中,ZHENGSHU 将起到和 int 相同的效果。

    //第二种
    using zheng_shu = ZHENGSHU;

使用了 using 关键字,将 zheng_shu 定义为 ZHENGSHU 类型的别名,作用与第一种类似。

 

《C++ Primer》第五版中特意写道,当const与复合类型的别名复合使用时,代码也许会出现意想不到的结果。

比如以下代码:

    //typedef类型别名定义,pstring等价于char指针类型
    typedef char* pstring;

此时,pstring 类型为一个 char* 类型,它是 char 类型和其指针类型的复合类型。

因此,当在 pstring 前面加上 const 时,事情就变得不那么简单了:

    //定义pstring底层常量c3, 底层指针c4
    const pstring c3 = 0;
    const pstring *c4;
    //此时报错,显示“表达式必须是可修改的左值”
    //意味着c3现在为一个顶层的常量指针
    c3 = c4;

熟悉 const 的大家一定都清楚,const 写在类型前面时,是一个底层 const 定义。

而 pstring 本身是一个 char* 类型,在前面的基础上,它需要指向一个 char 类型的指针常量。

此时c4为一个指向 pstring 类型指针的指针。

而在IDE中写下此段代码后,c3下面会弹出错误标识,提示你c3是一个不能修改的值。

这个时候就很奇怪了,为什么我用底层 const 定义出的指向常量的指针变成了一个常量指针?

 

而与此同时,用 char 类型复写一段同样的代码,就不会报错。

    //定义char指针c1,char常量d,char指针c2,均为底层const变量
    const char* c1 = 0;
    const char d = 'a';
    const char* c2 = &d;
    //可以看到,c2可以直接向c1赋值
    c1 = c2;

这里的c2是可以直接向c1进行赋值的,也意味着c1是可修改的。

 

那么,pstring 字段究竟发生了什么?

其实原书中给出了对应的解释:声明中用到pstring时,其基本数据类型是指针。可是用 char* 重写声明语句后,数据类型就变成了 char,*成为了声明符的一部分。

在改写后的代码中,const char 成了基本数据类型。因此,c1可以看做是一个指向 char 类型常量的指针。

而c3则作为一个 pstring 类型的常量被定义,这个定义等价于:

    const int i = 1;

只是 int 类型是一个数据类型,而 pstring 则是一个指针类型。

 

当我们理解原理后,再回过头来细品这个问题,就能够品味到C++语言中无处不在的细节。

 

希望这篇文章能帮助你更好理解这两个字段的复合使用~