C++之复合资料型态 第一部(参考 列举 指标)

复合资料型态(compound type) 是由其他资料型态(data type) 定义出来的型态, C++ 中的复合资料型态包括参考(reference) 、列举(enumeration) 、阵列(array) 、指标(pointer ) 、结构(structure) 及联合(union) 。

参考

参考是变数(variable) 的别名(alias) ,例如

#include <iostream>
  
int main() {
    int a = 22;
    int& a_ref = a;
    
    std::cout << "a: " << a << std::endl;
    std::cout << "a_ref: "<< a_ref << std::endl;
    
    a_ref = 11;
    std::cout << "a: " << a << std::endl;
    std::cout << "a_ref: " << a_ref << std::endl;
    
    return 0;
}

​ 第5 行,宣告参考的型态(type) 必须与参考所指向的变数型态相同,然后在型态名称后后使用& 运算子(operator) 标明这是个参考变数,因此这个例子的参考变数为a_ref,等号右边为所要指向的变数,此例为a ​

int& a_ref = a;

由于C++ 是自由格式的程式语言,因此写成int & a_ref或int &a_ref都可以。

接下来我们印出aa_ref的值,然后把a_ref改成11

a_ref = 11;

这样a也会变成11,编译后执行结果如下

$ g++ u0701_1.cpp
$./a.out 复制代码
答:22
参考编号:22
答:11
参考编号: 11
$

由上可看出参考等同于原来的变数,这被称为左值参考(lvalue reference) 。 C++11 增加了一个右值参考(rvalue reference) ,用以增进运算的效率,这是用&&来宣告,例如

int&& ref = a + b + c;

右值参考是对运算式的参考,举例如下

#include <iostream>
  
int main() {
    int a = 22;
    int b = 33;
    int c = 11;
    int&& ref = a + b + c;
    
    std::cout << "a: " << a << std::endl;
    std::cout << "b: " << b << std::endl;
    std::cout << "c: " << c
     << std::endl;
    std::cout << "ref: " << ref << std::endl;
    
    ref += 66;
    std::cout << "a: " << a << std::endl;
    std::cout << "b: "
     << b << std::endl;
    std::cout << "c: " << c << std::endl;
    std::cout << "ref: " << ref << std::endl;
    
    return 0;
}

编译后执行,结果如下

$ g++ u0701_2.cpp -std=c++0x
$./a.out 复制代码
答:22
乙:33
額: 11
参考:66
答:22
乙:33
額: 11
参考:132
$

列举

列举是一组整数常数,例如

#include <iostream>
  
int main() {
    enum Day {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday};
    
    std::cout << "Sunday: " << Sunday << std::endl;
    std::cout << "Monday: " << Monday << std::endl;
    std::cout << "Tuesday: " << Tuesday << std::endl;
    std::cout << "Wednesday: " << Wednesday << std::endl;
    std::cout << "Thursday: " << Thursday << std::endl;
    std::cout << "Friday: " << Friday << std::endl;
    std::cout << "Saturday: " << Saturday << std::endl;
    
    Day today = Wednesday;
    std::cout << today << std::endl;
    
    return 0;
}

第4 行,定义一个列举型态Day,使用关键字(keyword) enum,后面接着型态名称Day,然后大括弧中是列举的识别字(identifier) ,这被称为非作用域列举(unscoped enumeration )

enum Day {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday};

列举常数为从0开始递增的整数常数数列,因此第30 行宣告的today亦为整数常数,Wednesday是第4 个值,所以是整数3

Day today = Wednesday;

编译执行,结果如下

$ g++ u0702_1.cpp
$./a.out 复制代码
周日:0
星期一:1
星期二:2
星期三:3
星期四:4
周五:5
星期六:6
今天:3
$

列举也可以匿名(anonymous) 与指定起始整数,例如

#include <iostream>
  
int main() {
    enum {apple, banana = 11, orange, peach = 5};
    
    std::cout << "apple: " << apple << std::endl;
    std::cout << "banana: " << banana << std::endl;
    std::cout << "orange: " << orange << std::endl;
    std::cout << "peach: " << peach << std::endl;
    
    return 0;
}

此例的列举没有识别字,另外将banana设定为11,因此orange就由11递增为12,最后的peach则设定为5

enum {apple, banana = 11, orange, peach = 5};

编译后执行,结果如下

$ g++ u0702_2.cpp
$./a.out 复制代码
苹果:0
香蕉:11
橙色:12
桃子:5
$

列举也可以跟struct或class一起宣告,形成作用域列举(scoped enumeration) ,例如

enum class Color {RED, GREEN, BLUE};

C++11 中,列举常数可以改用其他型态,此时要在列举识别字后面加上冒号及型态名称,举例如下

#include <iostream>
  
enum class Color: char {
    RED = 'r',
    GREEN = 'g',
    BLUE = 'b',
};

int main() {
    Color r;
    r = Color::RED;
    Color g;
    g = Color::GREEN;
    Color b;
    b = Color::BLUE;
    
    std::cout << "RED: " << static_cast<char>(r) << std::endl;
    std::cout << "GREEN: " << static_cast<char>(g) << std::endl;
    std::cout << "BLUE: " << static_cast<char>(b) << std::endl;
    
    return 0;
}

这里定义一个作用域列举,并且将列举常数的型态指定为char

enum class Color: char {
    RED = 'r',
    GREEN = 'g',
    BLUE = 'b',
};

编译后执行,结果如下

$ g++ u0702_3.cpp -std=c++0x
$./a.out 复制代码
红色:r
绿色:g
蓝色:b
$

指标

指标是储存记忆体位址(address) 的资料型态,例如

#include <iostream>
  
int main() {
    int a = 22;
    int* a_ptr = &a;
    
    std::cout << "a_ptr: " << a_ptr << std::endl;
    std::cout << "*a_ptr: " << *a_ptr << std::endl;
    
    return 0;
}

第5 行,宣告指标的型态,必须与指标所指向的变数型态相同,然后在型态名称后使用* 运算子标明这是个指标变数,因此这个例子的参考变数为a_ptr,等号右边为所要指向的变数,此例为a,a之前的&则是取址运算子(address-of operator)

int* a_ptr = &a;

由于C++ 是自由格式的程式语言,因此写成int * a_ptrint *a_ptr都可以。

接下来先印出a_ptr的值,然后利用反参考运算子(dereference operator) *取得a_ptr所指向变数的值

std::cout << "a_ptr: " << a_ptr << std::endl;
std::cout << "*a_ptr: " << *a_ptr << std::endl;

编译后执行,结果如下

$ g++ u0704_1.cpp
$./a.out 复制代码
a_ptr:0x7fff50b81b08
*a_ptr: 22
$

注意,编译器(compiler) 会依据运算子出现的位置判断运算子的用途,例如

int* a_ptr; // 定义a_ptr为指标变数
int& a_ref; // 宣告 a_ref 为参考变数
a_ptr = &a; // & 为取地址侵犯子,取得一个的记忆体位址
*a_pr = 36; // * 为反参考进攻子,将设定为36

阵列识别字其实就是个指标,另外指标也可以作算术运算,例如

#include <iostream>

int main() {
    int a[] = {1, 2, 3, 4, 5};
    
    std::cout << "a[2]: " << *(a + 2) << std::endl;
    std::cout << "a[4]: " << *(a + 4) << std::endl;
    
    return 0;
}

这里用阵列名称与反参考运算子取得元素,指标的算术运算如同阵列的索引值,由于阵列名称为第1 个元素索引值为0的记忆体位址,所以加2就是索引值为2的元素记忆体位址,也就是第3 个元素,加4就是索引值为4的元素记忆体位址,也就是第5 个元素

std::cout << "a[2]: " << *(a + 2) << std::endl;
std::cout << "a[4]: " << *(a + 4) << std::endl;

编译后执行,结果如下

$ g++ u0704_2.cpp
$./a.out 复制代码
a[2]: 3
a[4]: 5
$

事实上,所有指标都预设能隐性转换指向void,举例如下

#include <iostream>
  
int main() {
    int n = 1;
    int* p = &n;
    void* p2 = p;
    int* p3 = static_cast<int*>(p2);
    
    std::cout << "n: " << n << std::endl;
    std::cout << "p: " << p << std::endl;
    std::cout << "*p3: " << *p3 << std::endl;
    
    return 0;
}

这里将指向int的指标重新指派给指向void的指标,转换回来要利用关键字 static_cast

int* p = &n;
void* p2 = p;
int* p3 = static_cast<int*>(p2);

编译后执行,结果如下

$ g++ u0704_3.cpp
$./a.out 复制代码
数量:1
p: 0x7fff55f89b18
*p3:1
$

C++11 新增一个关键字nullptr表示空的指标,等同于巨集NULL,举例如下

#include <iostream>
  
int main() {
    int n = 22;
    std::cout << "n: " << n << std::endl;
    
    int* p = &n;
    std::cout << "p: " << p << std::endl;
    
    p = nullptr; // NULL
    std::cout << "p: " << p << std::endl;
    
    return 0;
}

编译后执行,结果如下

$ g++ u0704_4.cpp
$./a.out 复制代码
人数:22
p: 0x7fff503acae8
p: 0x0
$

相关推荐

  1. C++复合资料 第一参考 列举 指标

    2024-07-13 18:06:02       20 阅读
  2. 搜索引擎参考Elasticsearch

    2024-07-13 18:06:02       44 阅读
  3. C++_多(函数指针)

    2024-07-13 18:06:02       45 阅读
  4. python复习 列表

    2024-07-13 18:06:02       31 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-13 18:06:02       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-13 18:06:02       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-13 18:06:02       58 阅读
  4. Python语言-面向对象

    2024-07-13 18:06:02       69 阅读

热门阅读

  1. spring-cloud和spring-cloud-alibaba的关系

    2024-07-13 18:06:02       19 阅读
  2. 4层负载均衡和7层负载均衡

    2024-07-13 18:06:02       20 阅读
  3. 大话C语言:第31篇 指针和数组的关系

    2024-07-13 18:06:02       21 阅读
  4. 算法提高第二章 线段树基础

    2024-07-13 18:06:02       17 阅读
  5. django orm中value和value_list以及转成list

    2024-07-13 18:06:02       21 阅读
  6. C# .Net Core Zip压缩包中文名乱码的解决方法

    2024-07-13 18:06:02       21 阅读
  7. live555关于RTSP协议交互流程

    2024-07-13 18:06:02       15 阅读
  8. EXPORT_SYMBOL

    2024-07-13 18:06:02       24 阅读