传统的定义别名的方法是使用关键字 typedef
typedef double wages; // wages 是 double 的同义词
typedef wages base, *p; // base 是 double 的同义词,p 是 double* 的同义词
新标准规定了一种新的方法,使用 别名声明 来定义类型的别名:
class CollegeStudents
{
public:
CollegeStudents() {}
// ...
};
using CS = CollegeStudents;
使用示例:
wages hours, weeks;
CS someone;
** 指针、常量和类型别名 **
如果某个类型别名指代的是复合类型或常量,那么把它用到声明语句里就会产生意想不到的后果。例如下面的声明语句用到了类型 pstring,它实际上是类型 char* 的别名:
typedef char * pstring;
const pstring nullstr0 = nullptr;
const pstring *ps;
上面两条声明语句的基本类型都是 const pstring,const 是对给定类型的修饰。pstring 实际上是指向 char 的指针,因此,const pstring 就是指向 char 的常量指针,而非指向常量字符的指针。
遇到一条使用了类型别名的声明语句时,乡亲们往往会错误地尝试把类型别名替换成它本来的样子,以理解该语句的含义:
const char * nullstr1 = nullptr;
然而,乡亲们,这种理解是错误的。声明语句中用到 pstring 时,其基本数据类型是指针。可是用 char * 重写了声明语句后,数据类型就变成了 char,* 成为了声明符的一部分。这样改写的结果是, const char 成了基本数据类型。前后两种声明含义截然不同,前者声明了一个指向 char 的常量指针,改写后的形式则声明了一个指向 const char 的指针。
使用如下代码测试 ps、nullstr0、nullstr1 的类型:
#include <QCoreApplication>
#include <cxxabi.h>
#include <QDebug>
#include <typeinfo>
#include <iostream>
#include <string>
#include <memory>
#include <cstdlib>
namespace {
std::string demangle(const char* mangled)
{
int status;
std::unique_ptr<char[], void (*)(void*)> result(
abi::__cxa_demangle(mangled, nullptr, nullptr, &status), std::free);
return result.get() ? std::string(result.get()) : "error occurred";
}
template<class T>
void foo(T t) { std::cout << demangle(typeid(t).name()) << std::endl; }
typedef char * pstring;
const pstring nullstr0 = nullptr;
const pstring *ps;
const char * nullstr1 = nullptr;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
foo(ps);
foo(nullstr0);
foo(nullstr1);
return a.exec();
}
输出结果为:
char* const*
char*
char const*
网友评论