【C++笔记】三、复杂数据类型(上)

1.数组基础

1.1 数组的定义

//  typeName arrayName[arraySize]
    long productIds[199];

1.2 数组的优点和缺点

#include <iostream>
using namespace std;
int main(int argc, const char * argv[])
{
    long productIds[199];
//优点:可以随意获取数组元素
    productIds[0] = 20;
    productIds[1] = 30;
    productIds[2] = productIds[0] * productIds[1];
/*缺点:对数组元素进行插入/删除,会导致整个数组的移动,具体移动的个数,取决于所插入/删除得元素在数组中的所在位置*/
    return 0;
}

1.3 获取数组的长度

#include <iostream>
using namespace std;
int main(int argc, const char * argv[])
{

    long productIds[199];

    productIds[0] = 20;
    productIds[1] = 30;
    productIds[2] = productIds[0] * productIds[1];
    
    cout << "数组占的总字节数:" << sizeof productIds << endl;    //打印1592
    cout << "数组长度:" << sizeof productIds / sizeof(long) << endl;  //打印199

    return 0;
}

2.数组初始化

2.1 传统的数组初始化方式

//正确
int number[4] = {3,6,9,12};

//错误
int productIds[4];
productIds[3] = {1,2};

//错误,不能用一个数组名初始化另一个数组
productIds = number;

//正确  没有进行初始化的数组元素都会设为0
float values[5] = {5.0,2.1};

2.2 数组清零(传统的方式和C++ 11中的方式)

//传统方式
float totals[200] = {0};

//C++11中的方式
float totals[200] = {};   //全零

2.3 C++ 11中的数组初始化方式

double c11_values1[4] {1.2,3.3,4.4,5.5};   //可以不需要等号
double c11_values2[] {1.2,3.3,4.4,5.5};   //可以不指定长度,会自动检测

2.4 C++ 11中的数组元素类型检测

short years[] = {25, 12,1.0}; //会报错,1.0默认为double类型,无法转换成short

char c_array[] = {'a','b',123};  //char最多能表示到127,所以123是可以转换成char的

int x = 123;
char c_array1[] = {'a','b', x}; //报错,C++编译器无法继续检测x的类型/范围

int x = 123;
char c_array1[] = {'a','b',(char)x};  //正确

3.C风格的字符串

3.1 C风格字符串的存储格式

        在字符串结尾有一个ASCII值为0的字符,即转义字符' \0 ',当系统读到' \0 '时,就会认为字符串结束,无论' \0 '后面有什么,全部扔掉。


3.2 C风格字符串变量的定义和初始化

//定义C风格的字符串有两种方式: 1.数组  2.指针

//1.数组
char str1[6] = {'a','b','c','d','e','\0'};  //是一个字符串,转义字符占用一个位置
char str2[6] = {'a','b','c','d','e','f'};   //不是字符串,只是一个普通的char类型数组

char str1[6] = {'a','b','c','\0','e','\0'};
cout << str1 << endl;            //打印: abc

char str1[6] = {'a','b','c','d','e','\0'};
cout << str1 << endl;            //打印: abcde

char str1[6] = {'a','b','c','\0','e','\0'};
cout << *(str1+4) << endl;       //打印: e


char str3[6] = "abc";      //给'\0'预留了位置,是字符串
char str4[] = "abcdefdsfslfsdjsdfljjlsdljfd";    /*也可以不指定空间的字节数,C++编译器会自动检测长度,并在后面加上'\0'  */


//2.指针
char *pstr = "abcd";    //自动分配了5字节空间(包括了'\0')
cout << pstr << endl; 

3.3 字符串连接

char str5[] = "abcd""abc";  //打印:abcdabc
cout << str5 << endl;         //不能连接字符串与字符串变量
cout << "xyz""123" << endl;  //打印 xyz123

3.4 获取字符串长度

char str3[6] = "abcde";
cout << strlen(str3) << endl;   //打印 5 

char str3[6] = "abc";
cout << strlen(str3) << endl;   //打印 3  和数组大小无关,长度不包含'\0'的部分

3.5 枚举字符串中的字符

#include <iostream>
using namespace std;
int main(int argc, const char * argv[])
{   
    char str3[6] = "abc";

    int n = strlen(str3);

//数组的方式
    for(int i = 0; i < n; i++)
    {
        cout << "<" << str3[i] << ">";
    }
    cout << endl;

//指针的方式
    for(int i = 0; i < n; i++)
    {
        cout << "<" << *(str3 + i) << ">";
    }
    cout << endl;

    return 0;
}

//打印 <a><b><c>

4.C风格字符串的输入

4.1. cin >> ...输入方式

#include <iostream>
using namespace std;
int main(int argc, const char * argv[])
{  
    int size = 10;
    char name[size];   //size = 10 但最多存9个字符
    cout << "请输入你的名字:";
    cin >> name;
    //name[9] = '\0';
    cout << "你的名字是:" << name << endl;

    return 0;
}
#include <iostream>
using namespace std;
int main(int argc, const char * argv[])
{  
    int size = 10;
    char name[size];   //size = 10 但最多存9个字符
    cout << "请输入你的名字:";
    cin >> name;
    name[9] = '\0';    //可以防止即使输入字符串长度超过9,也能正常输出
    cout << "你的名字是:" << name << endl;

    return 0;
}

4.2. getline输入方式

#include <iostream>
using namespace std;
int main(int argc, const char * argv[])
{    
    char city[20];
    cout << "请输入你所在的城市:";
    cin >> city;
    cout << "你所在的城市是:" << city << endl;

    return 0;

}

//当输入中间带有空格的内容时,比如New York,只会打印 New
#include <iostream>
using namespace std;
int main(int argc, const char * argv[])
{    
    char city[20];
    char s[20];
    cout << "请输入你所在的城市:";
    cin >> city >> s;
    cout << "你所在的城市是:" << city << endl;
    cout << s << endl;

    return 0;

}

//输入New York时,把New给到city,把York给到s,但输出是分开的
//  istream.getline方法
cin.getline(city, 20);    //读到回车会自动忽略回车,最多输入19个字符,最后一个字符被设为'\0'
cout << "你所在的城市是:" << city << endl;

4.3. get输入方式

此时输入New York,按回车会打印:

        因为get区别于getline,get会读取回车符,那么此时city1读取到了New York,city2读取了空行,并按回车进行了输出。解决方法如下:

  // 方法一
char city1[20];
char city2[20];
cout << "城市1:";
cin.get(city1, 20);
cin.get();             //把回车消耗掉
cout << "城市2:";
cin.get(city2, 20);
cout << "城市1:" << city1 << endl;
cout << "城市2:" << city2 << endl;


  // 方法二
char city1[20];
char city2[20];
cout << "城市1:";
cin.get(city1, 20).get();   //效果等同于上者,只是形式不同
 
cout << "城市2:";
cin.get(city2, 20);
cout << "城市1:" << city1 << endl;
cout << "城市2:" << city2 << endl;

4.4. 字符串和数字混合输入

int year;
char name[20];
(cin >> year).get();   // 把回车吃掉,若不吃掉,则getline会把回车符当作输入
cin.getline(name, 20);
cout << "year:" << year << endl;
cout << "name:" << name << endl;

5.C++风格的字符串:string类

5.1 声明string类型的变量

char str1[] = "hello world";  //C风格声明字符串
string str2 = "hello world";  //C++风格,string属于标准命名空间std中

C++风格的字符串后面没有'\0'

5.2 初始化string类型的变量(包括C++ 11的初始化方式)

string str3 = {"Hello world"};
string str4 {"hello world"};  // C++ 11

5.3 输入输出string类型的变量值

cout << "请输入str1:";
cin >> str1;
cout << "str1=" << str1 << endl;
cout << "请输入str2:";
cin >> str2;
cout << "str2=" << str2 << endl;

5.4 获取string类型变量值中的指定字符

for(int i = 0; i < str2.length();i++)
{
    cout << "<" << str2[i] << ">" << endl;
}

6.字符串的复制、连接和获取长度

6.1 字符串的复制

//  C++字符串的复制
string str1 = "abc";
string str2 = str1;
cout << "str2 = " << str2 << endl;

//str1.c_str()将C++风格的字符串转换为C风格的字符串
const char *p = str1.c_str();
cout << "p=" << p << endl;


//  C字符串的复制--strcpy
char c_str1[] = "hello";
char c_str2[6];   //当c_str2大小为4时,就只能复制3个字符到c_str2了

strcpy(c_str2,c_str1);   //strcpy(目标字符串,源字符串);
cout << "c_str2=" << c_str2 << endl;


//  C字符串的复制--strncpy
char c_str1[] = "hello";
char c_str2[4];  

strncpy(c_str2,c_str1,3);   //strncpy(目标字符串,源字符串,复制字符串的长度(不包含'\0'));
cout << "c_str2=" << c_str2 << endl;

6.2 字符串的连接

    //  C++字符串连接
str2 += str1;   // str2 = str2 + str1;
cout << "str2=" << str2 << endl;
    
    // C字符串连接
//hello和空格占了6个字符位置,再加上'\0',一共占了7个位置,最多再往里放三个字符
char c_str3[10] {"hello "}; 
char c_str4[] {"world"};
    
//    strcat(c_str3, c_str4);     //strcat(前面的字符串, 后面的字符串);
//即,将c_str4中的字符放入c_str3中,所以要保证c_str3有足够的空间

strncat(c_str3, c_str4, 3);  //只能在后面追加3个字符
cout << "c_str3=" << c_str3 << endl;

6.3 获取字符串长度

    //  获取字符串的长度
int len1 = str1.length();  // C++风格字符串
int len2 = strlen(c_str3);  // C风格字符串

7.宽字符串与Raw String

7.1 宽字符串

string str1 = "中花";   //C++风格字符串
char c_str[] = "中";    //C风格字符串,通过数组方式定义
wchar_t wc_str[] = L"中";   //宽字节,有符号类型 32位  4字节  在定义时前加前缀L

cout << "str1 length:" << str1.length() << endl;   //C++风格获取字符串长度,字符个数
cout << "c_str length:" << sizeof(c_str) / sizeof(char) << endl;
cout << "c_str byte length:" << sizeof(c_str) << endl;    //字节长度
cout << "wc_str length:" << sizeof(wc_str) / sizeof(wchar_t) << endl;
cout << "wc_str byte length:" << sizeof(wc_str)  << endl;

①对于str1,是C++风格的字符串,不考虑'\0',每个中文占3字节
②对于c_str,是C风格的字符串,考虑'\0',中文占用3字节,'\0'占1字节,所以共有4个char,每个char1字节,总长度4字节
③对于宽字节wchar_t,不管是什么字符,都占用4字节,即'\0'也占用4字节,所以共有2个wchar_t,总字节长度为8

输出结果:

// char16_t   无符号类型 2字节  在定义时前加前缀u  
// char32_t   无符号类型 4字节  在定义时前加前缀U   等同于wchar_t

char16_t w16_char[] =u"中"; 
cout << "w16_char length:" << sizeof(w16_char) / sizeof(char16_t) << endl;   //  2
cout << "w16_char byte length:" << sizeof(w16_char)  << endl;        //  4

7.2 Raw String

cout << "Hello \\n World" << endl;   //想要直接输出\n,需要加转义字符

//无需加转义字符,括号中的内容不做任何处理,记得加括号
cout << R"(Hello \n \n \ World)" << endl;  

cout << R"((Hello \n \n \ World))" << endl;   //再加一层括号,就能输出括号了

//括号的开头和结尾部分要匹配,即,开头部分加xyz的话,末尾部分也要加,才能把中间的内容原样输出
cout << R"xyz((Hello \n (aa)\n \ World))xyz" << endl;  

8.结构体的定义、初始化和使用

8.1 结构体的定义

// 可以在函数里/外定义 ,几种写法
struct MyStruct
{
     int code;
     string name;
     float salary;

} myStruct1;


// 几种写法
MyStruct myStruct5 = MyStruct();

MyStruct myStruct2;  //  C语言需要在最前方添加struct关键字,C++不需要

auto myStruct3 = new MyStruct();  //auto会自动识别为结构体指针

auto mySturct4 = MyStruct();

8.2 结构体的初始化

struct MyStruct
{
     int code;
     string name;
     float salary;
} myStruct1 = {20,"bill", 2550};

MyStruct myStruct5 = MyStruct();   //无法初始化,只能一个一个的修改成员变量

MyStruct myStruct2  = {20,"bill", 2550};  //  C语言需要添加struct关键字,C++不需要

MyStruct myStruct2 {20,"bill", 2550};    //C++11 

auto myStruct3 = new MyStruct();

auto mySturct4 = (MyStruct){20,"bill", 2550};

8.3 结构体的使用

auto myStruct3 = new MyStruct();      // myStruct3是指针
auto mySturct4 = (MyStruct){20,"bill", 2550};  // mySturct4是结构体变量
   
mySturct4.code = 200;
mySturct4.name = "abc";
mySturct4.salary = 20.3;
    
cout << mySturct4.name << endl;

// myStruct3是结构体指针
myStruct3->name = "ABC";

9.结构体数组

#include <iostream>
using namespace std;

int main(int argc, const char * argv[])
{
    
    struct MyStruct
    {
        int code;
        string name;
        int values[2];
    };
    
    MyStruct myStructArray1[100];   //定义了一个结构体类型的数组
    myStructArray1[0].name = "bill";   //设置结构体数组中第一个元素的成员变量name
    cout << myStructArray1[0].name << endl;
    
//初始化结构体数组,方式一
    MyStruct myStructArray2[2] = {{20, "Mary",{1,2}}, {30, "John", {3,4}}};  //全部花括号
    cout << myStructArray2[0].values[1] << endl;

/*  初始化结构体数组,方式二,用auto时,等号右侧的内容一定要能定义左侧的类型,所以才要加上(MyStruct[])  */
    auto myStructArray3 = (MyStruct[]){{20, "Mary",{1,2}}, {30, "John", {3,4}}};
    cout << myStructArray3[1].name << endl;
    
    return 0;
}

10.计算结构体的尺寸

10.1 结构体尺寸的计算规则

        在默认情况下,结构体尺寸是结构体中占字节最多的成员变量的尺寸的整数倍
        更通用的说法:结构体尺寸是当前对其方式的整数倍

struct MyStruct1
{
     int code1;
     int code2;
};

cout << "MyStruct1 size:" << sizeof(MyStruct1) << endl;   // 8


struct MyStruct2
{
     short code1;
     char c;
} myStruct2{20,'a'};

cout << "MyStruct2 size:" << sizeof(MyStruct2) << endl;   // 4

10.2 结构体的对齐方式

struct MyStruct2
{
     short code1;
     char c;
} myStruct2{20,'a'};

unsigned int *n1 = (unsigned int*)&myStruct2;   //n1是地址(指针),指向结构体
bitset<32> b1(*n1);   
cout << "myStruct2二进制表示:" << b1 << endl;  // 00000000011000010000000000010100


从低位往高位存,20存到低16位,再存'a'
'a' : (十进制ASCII)97  (二进制) 01100001   —— char类型 1字节 8位    对齐补零后:16位
20  :(二进制) 0000000000010100   —— short类型 2字节 16位



//  如果结构体成员变量默认的对齐方式与修改后的对齐方式冲突,以最小的为准
struct MyStruct3
{
     char c;
     short code1;
} myStruct3{'a',20};   // 20和'a'进行了调换
    
cout << "MyStruct3 size:" << sizeof(MyStruct3) << endl;
    //  结构体的对齐方式
unsigned int *n2 = (unsigned int*)&myStruct3;
bitset<32> b2(*n2);
cout << "myStruct3二进制表示:" << b2 << endl;    // 4

10.3 修改结构体默认的对齐方式

//如果结构体成员变量默认的对齐方式与修改后的对齐方式冲突,以最小的为准
#include <iostream>
using namespace std;
#pragma pack(1)      //改变对齐方式 :以1字节为单位,结构体尺寸是1字节的整数倍
int main(int argc, const char * argv[])
{

    struct MyStruct2
    {
         short code1;
         char c;
    } myStruct2{20,'a'};

// 默认对齐方式:2  修改后的对齐方式:1 ,以1为准
    cout << "MyStruct2 size:" << sizeof(MyStruct2) << endl;   // 3

    return 0;
}


#include <iostream>
using namespace std;
#pragma pack(2)      //改变对齐方式 :以2字节为单位,结构体尺寸是2字节的整数倍
int main(int argc, const char * argv[])
{

    struct MyStruct2
    {
         short code1;
         char c;
    } myStruct2{20,'a'};

    cout << "MyStruct2 size:" << sizeof(MyStruct2) << endl;   // 4

    return 0;
}


#include <iostream>
using namespace std;
#pragma pack(4)   //如果结构体成员变量默认的对齐方式与修改后的对齐方式冲突,以最小的为准    
int main(int argc, const char * argv[])
{

    struct MyStruct2
    {
         short code1;
         char c;
    } myStruct2{20,'a'};

// 默认对齐方式:2  修改后的对齐方式:4  ,以2为准
    cout << "MyStruct2 size:" << sizeof(MyStruct2) << endl;   // 4

    return 0;
}

10.4 空结构体的尺寸

struct NullStruct
{
        
};
cout << "NullStruct Size:" << sizeof(NullStruct) << endl;   // 1

总是1 ,不受#pragma pack(1)影响

11.结构体的位字段

11.1 定义、初始化位字段

#include <iostream>
using namespace std;

int main(int argc, const char * argv[])
{
    struct MyStruct1
    {
        unsigned int code1;
        unsigned int code2;
        bool flag;
    };

    struct MyStruct2
    {
        unsigned int code1:4;    //占了4位
        unsigned int code2:4;
        bool flag:1;
    } myStruct2{17,15,false};


    cout << sizeof(MyStruct1) << endl;   //12字节

/* 4字节 ,默认对齐是4字节,那么MyStruct2的尺寸应该是4的整数倍,因为MyStruct2一共占9位,那么4字节够用了 */
    cout << sizeof(MyStruct2) << endl;   //4字节  
    cout << myStruct2.code2 << endl;   //打印: 1  为什么?

    struct MyStruct3
    {
         unsigned int code1:18;    //占了18位
         unsigned int code2:14;
         bool flag:1;
    } myStruct3{17,15,false};

 //8字节,MyStruct3一共占了33位,4字节不够用了,所以是8字节
    cout << sizeof(MyStruct3) << endl;  

11.2 位字段是如何存储的?如果位字段溢出,会发生什么?

struct MyStruct2
{
     unsigned int code1:4;
     unsigned int code2:4;
     bool flag:1;

} myStruct2{17,15,false};

cout << myStruct2.code2 << endl;   //打印: 1  为什么?

// 以二进制形式输出
unsigned int *n = (unsigned int*)(&myStruct2);
bitset<32> b(*n);
cout << b << endl;   //打印 00000000000000000000000011110001

存储方式:从结构体的第一个成员开始,从低位往高位存,即:
00000000000000000000000  0   1111   0001
                       false  15     17
myStruct2.code1只取存储中的低四位,又因为17对应的二进制是 10001,所以17被截断了,只剩下0001

12.共用体或联合体(Union)

12.1 union的定义与尺寸

#include <iostream>
using namespace std;
int main(int argc, const char * argv[])
{

 //  共用体中所有的成员变量,同时只能使用一个
    union MyUnion1
    {
        int code1;
        long long code2;
        float price;
        bool flag;
    } myUnion;

    cout << "MyUnion1 size:" << sizeof(MyUnion1) << endl;  // 8

    struct MyStruct
    {
        int code1;
        long long code2;
        float price;
        bool flag;
    } myStruct{20,30,10.4,true};

    cout << "MyStruct size:" << sizeof(MyStruct) << endl;  // 24(字节),8的整数倍

    union MyUnion2
    {
        int code1;
        long long code2:4;   // 有符号或无符号决定于变量类型是有符号还是无符号
        float price;
        bool flag;
    } myUnion2;

    cout << "MyUnion2 size:" << sizeof(MyUnion2) << endl;    // 8(字节)

12.2 union是否能像struct一样初始化

不能像结构体一样初始化联合体,因为union同时只能使用一个变量
如果设置某一个变量,会覆盖union中的其他变量,比如MyUnion1中的float price是用了long long code2的低4个字节

union MyUnion1
{

     int code1;
     long long code2;
     float price;
     bool flag;

} myUnion;

myUnion.price = 10.1;
cout << "myUnion.price=" << myUnion.price << endl;  // 打印10.1  
myUnion.code2 =100;         // 将myUnion.price覆盖
cout << "myUnion.price=" << myUnion.price << endl;  // 打印的不是10.1 

12.3 union中的位字段

    union MyUnion2
    {
        int code1;
        long long code2:4;   // 有符号或无符号决定于变量类型是有符号还是无符号
        float price;         // 4位二进制最多表示15
        bool flag;

    } myUnion2;

    myUnion2.code2 = 17;     //大于15,会溢出

    cout << "myUnion2.code2=" << myUnion2.code2 << endl;   // 1 
    cout << "MyUnion2 size:" << sizeof(MyUnion2) << endl;   // 8

    myUnion2.code2 = 13;     //小于15,不会溢出

    cout << "myUnion2.code2=" << myUnion2.code2 << endl;   //  -3 ,为什么不是13?   
    cout << "MyUnion2 size:" << sizeof(MyUnion2) << endl;   //  8

12.4 union的二进制存储形式

union MyUnion2
{
     int code1;
     long long code2:4;   // 有符号或无符号决定于变量类型是有符号还是无符号
     float price;         
     bool flag;
} myUnion2;

cout << "myUnion2.code2=" << myUnion2.code2 << endl;   //  -3 ,为什么不是13?  

//常用的查看二进制存储形式的代码段,要记住

unsigned long long *n = (unsigned long long*)&myUnion2;
bitset<64> b(*n);
cout << b << endl;   // 0000000000000......000001101

1101对应的是13,为什么打印了-3?
原因在于long long是有符号的类型,所以会认为4位的long long code2是有符号的
以补码的形式存在,最高位是符号位,补码:1101   原码:1011 对应-3
所以若在union中定义的是unsigned long long code2,就会正常输出13了

13.枚举类型

13.1 枚举类型的定义

enum color{red,yellow,green,blue};  //定义枚举类型 color
             0    1     2      3

color flowerColor;  //定义枚举类型变量flowerColor

13.2 枚举类型成员的默认值

enum color{red,yellow,green,blue};  //定义枚举类型 color
             0    1     2      3

13.3 为枚举类型变量赋值

flowerColor = green;   //为枚举类型赋值
cout << "flowerColor=" << flowerColor << endl;   //打印 2


flowerColor = 1;   //报错
flowerColor = (color)1;   //进行强制类型转换
if(flowerColor == yellow)
{
     cout << "color:yellow" << endl;    // color:yellow
}


flowerColor = red + green;   //报错
flowerColor = (color)(red + green);//进行强制类型转换
if(flowerColor == green)
{
     cout << "flowerColor:green" << endl;   // flowerColor:green
}


int value = flowerColor + 10;   
cout << "value:" << value << endl;    // 12

14.设置/指定枚举类型成员的值

enum Color1{RED1, GREEN1, BLUE1};
              0      1       2
//引用枚举类型成员使用'::'
cout << "Color1::GREEN1=" << Color1::GREEN1 << endl;  // 1

enum Color2{RED2, GREEN2 =20, BLUE2};
cout << "Color2::GREEN2=" << Color2::GREEN2 << endl;   // 20
cout << "Color2::BLUE2=" << Color2::BLUE2 << endl;     // 21 枚举类型成员值会顺着前一项加一

// C++允许两个或多个枚举类型成员的整型值相同
enum Color3{RED3, GREEN3 = 0, BLUE3,YELLOW3=1 };
cout << "Color3::RED3=" << Color3::RED3 << endl;        // 0
cout << "Color3::GREEN3=" << Color3::GREEN3 << endl;    // 0
cout << "Color3::BLUE3=" << Color3::BLUE3 << endl;      // 1
cout << "Color3::YELLOW3=" << Color3::YELLOW3 << endl;  // 1

Color3 color3 = Color3(1);     //整型1是可以对应多个枚举类型成员的
if(color3 == Color3::BLUE3)
{
     cout << "equal" << endl;    // equal
}
if(color3 == Color3::YELLOW3)
{
     cout << "equal" << endl;    // equal
}

// 枚举类型成员的整型值是允许为负数的
enum Color4{RED4 = -2, GREEN4, BLUE4 };
cout << "Color4::RED4=" << Color4::RED4 << endl;     // -2
cout << "Color4::GREEN4=" << Color4::GREEN4 << endl; // -1
cout << "Color4::BLUE4=" << Color4::BLUE4 << endl;   //  0

// 枚举类型成员可以赋值字符,但存进去的是字符所对应的ASCII值,'A'对应65
enum Color5{RED5 = 'A', GREEN5, BLUE5 };
cout << "Color5::RED5=" << Color5::RED5 << endl;     // 65
cout << "Color5::GREEN5=" << Color5::GREEN5 << endl; // 66

15.枚举类(enum class):C++ 11新特性

// 传统C++中,枚举成员是全局的,在不同的枚举类型中,各自的枚举成员是不能同名的
enum  Color1{RED, GREEN, BLUE};
enum Color2{RED1, GREEN1, BLUE1};

Color1 color1 = Color1::RED;
if(Color1::RED == color1)    //在传统的C++中,if(0 == color1)这种表达方式也可以,但可读性很差
{
     cout << "color1 == Color1::RED" << endl;   // color1 == Color1::RED
}

// C++11枚举类enum class,区别:允许相同的枚举成员,且不允许if(0 == color1)这种表达方式
//即,不能自动将color1转换为数值
enum class Color3{RED, GREEN,BLUE = 20};
enum class Color4{RED, GREEN,BLUE};

Color3 color3 = Color3::GREEN;
if(Color3::GREEN == color3)
{
        
}
cout << int(Color3::BLUE) << endl;   // 需要强制类型转换后,方能输出数值
cout << Color1::BLUE << endl;    //可以自动转换为数值

16.枚举类型的尺寸

16.1 计算枚举类型的尺寸

// 枚举类型的每一个成员默认对应一个int类型的值
enum Color1{RED,GREEN,BLUE};
cout << "Color1 size=" << sizeof(Color1) << endl;   // 4(字节)

// 可以使用/*  */ 在代码中间增加注释
// INT8_MAX   127   8位二进制最大值
// INT16_MAX  32767   16位二进制最大值
enum class Color2{RED = INT32_MAX-2,GREEN ,BLUE /*= INT32_MAX + 1:溢出,会出错*/};
cout << "Color2 size=" << sizeof(Color2) << endl;    // 4(字节)

16.2 枚举类型成员对应的值的溢出

// BLUE的值超过了int的存储范围,所以会报错
enum class Color2{RED = INT32_MAX-2,GREEN ,BLUE = INT32_MAX + 1};

// 依然会报错,因为RED已经是最大,那GREEN和BLUE会按顺序加一,导致溢出
enum class Color2{RED = INT32_MAX,GREEN ,BLUE};

16.3 修改枚举类型的尺寸

enum class Color3:short{RED,GREEN,BLUE = INT16_MAX};
cout << "Color3 size=" << sizeof(Color3) << endl;    // 2
    
enum class Color4:unsigned char{RED,GREEN,BLUE = 255};   //无符号1字节,最大255
cout << "Color4 size=" << sizeof(Color4) << endl;    // 1
    
//  C++ 11
// 有符号8位,127到-128, BLUE如果是-128的话,RED和GREEN并不会按顺序往前减一,而是从0开始
enum class Color5:int8_t{RED,GREEN,BLUE = -128};   
cout << int(Color5::RED) << endl;    // 0          
cout << int(Color5::GREEN) << endl;  // 1

17.匿名类型和类型别名

17.1 匿名类型

// MyStruct  MyUnion有时可以省略
// 结构体、共用体定义
struct MyStruct 
{
    int code;
    string name;
};

union MyUnion
{
    int code;
    long code1;
};

// 匿名结构体 ,后面必须跟变量
struct 
{
    int code;
    string name;
}product;
product.name = "abc";

// 匿名共用体,后面可以不跟变量
union
{
    int code;
    long code1;
};

union
{
    int code;
    long code1;
}myCode;

// 枚举类型定义
enum enum_name{ONE,TWO,THREE};  //这种情况要是想使用枚举成员,就需要enum_name::ONE来调用
// 匿名枚举,可以不跟变量
enum {ONE,TWO,THREE};
enum {ONE,TWO,THREE} value;  //这种情况枚举成员ONE,TWO,THREE是全局的,不需要'::'来调用
value = ONE;

// 即便是C++枚举类,若用匿名枚举类,那么成员ONE,TWO,THREE仍然是全局的
// 不能和其他枚举类型和匿名枚举类的成员相同
enum class {ONE,TWO,THREE} value1; 

enum class abc{ONE,TWO,THREE} value1;  //成员ONE,TWO,THREE变成了局部

17.2 类型别名

// typedef

typedef struct 
{
    int code;
    string name;
}product_type;
product_type p;   // product_type为类型别名,可以用来定义结构体变量
p.name = "xuz";

typedef union
{
    int code;
    long code1;
}myCode_type;
myCode_type code;   // myCode_type 为类型别名,可以用来定义共用体变量
code.code1 = 1000;

// 对于匿名枚举类型来说,所有枚举成员(枚举值)都是全局的,不属于某个特定变量
typedef enum {ONE1,TWO1,THREE1} value_type;  // value_type是一个类型,枚举类型
value_type v1 = ONE1;

typedef enum class {ONE2,TWO2,THREE2} value_type1;   //value_type1可以定义枚举类变量
value_type1 v2 = ONE2;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DUANDAUNNN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值