C++中类型和类型转换

本文介绍 C++ 中的类型转换。

涉及 type 的一些概念

Incomplete type

  1. void 以及其 cv-qualified 形式
  2. incompletely-defined object type
    一个 class 被声明(比如一个前向声明),却没有定义。
    bound 未知的数组。
    imcomplete type 构成的数组。
    enum,从它的声明,到它的 underlying type 被确定期间。

这里说明一下,bound 未知的数组未必是 flex 数组。它可能是如下面这种 extern 形式定义的

1
2
3
4
5
extern int x[];      // the type of x is "array of unknown bound of int"
int a[] = {1, 2, 3}; // the type of a is "array of 3 int"

extern int a[][2]; // okay: array of unknown bound of arrays of 2 int
extern int b[2][]; // error: array has incomplete element type

在下列情况下,需要类型是 Complete 的:

  1. TODO

typd-id

我们可以通过 class/union/enum/typedef/using(type alias) 这些方式定义一个具名的类型。但是在 C++ 中,我们经常使用那些不具名的类型,例如下面的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int* p;               // declaration of a pointer to int
static_cast<int*>(p); // type-id is "int*"

int a[3]; // declaration of an array of 3 int
new int[3]; // type-id is "int[3]" (called new-type-id)

int (*(*x[2])())[3]; // declaration of an array of 2 pointers to functions
// returning pointer to array of 3 int
new (int (*(*[2])())[3]); // type-id is "int (*(*[2])())[3]"

void f(int); // declaration of a function taking int and returning void
std::function<void(int)> x = f; // type template parameter is a type-id "void(int)"
std::function<auto(int) -> void> y = f; // same

std::vector<int> v; // declaration of a vector of int
sizeof(std::vector<int>); // type-id is "std::vector<int>"

struct { int x; } b; // creates a new type and declares an object b of that type
sizeof(struct { int x; }); // error: cannot define new types in a sizeof expression
using t = struct { int x; }; // creates a new type and declares t as an alias of that type

sizeof(static int); // error: storage class specifiers not part of type-specifier-seq
std::function<inline void(int)> f; // error: neither are function specifiers

此外,RTTI 机制还提供了一个 typeid 运算符(不是函数)

1
2
3
4
5
int main() {
assert(typeid(int&) != typeid(int*));
assert(typeid(int) == typeid(int));
return 0;
}

显式类型转换

显式转换有几种类型:

(new-type) expr型。这是 C-style 的,C++ 会按顺序尝试:

  1. const_cast
  2. static_cast(增强的)
    注意,子类的指针或者引用,可以被转成无歧义的基类,即使基类不可访问。对于成员函数的指针也同样适用
  3. static_cast(增强的) + const_cast
  4. reinterpret_cast
  5. reinterpret_cast + const_cast

new-type (expr)型。

需要注意,这种 function-style cast expression 容易和声明产生歧义。此时,这些歧义都会被视作声明。

1
2
3
4
5
6
7
8
9
10
struct M {};
struct L { L(M&); };

M n;
void f()
{
M(m); // declaration, equivalent to M m;
L(n); // ill-formed declaration
L(l)(m); // still a declaration
}

【C++11起】new-type {expr}型。

一个显式类型转换的类型是什么呢?

  1. 对于 lvalue reference,结果是一个 lvalue
  2. 对于函数的 rvalue reference,结果是一个 lvalue
  3. 对于 rvalue reference,结果是一个 xvalue
  4. 对于其他情况,结果是一个 prvalue

隐式类型转换

Reference

  1. https://en.cppreference.com/w/cpp/language/explicit_cast
  2. https://en.cppreference.com/w/cpp/language/type