C++的类型

C++的类型

按照标准,C++只有两种类型:基本类型和复合类型,但是里面细节多导致彻底理解它们有难度,所以这里只是简单总结一下。

基本类型

基本类型分成算术类型和两种特殊的类型。

算术类型

算术类型分成整数类型和浮点数类型两种。

整数类型

以下都是整数类型:

有符号整数类型无符号整数类型
标准整数类型标准有符号整数类型标准无符号整数类型
扩展整数类型扩展有符号整数类型扩展无符号整数类型

下面两个是属于上面的标准整数类型部分:

  • 标准有符号整数类型:signed char,short int,int,long int,long long int
  • 标准无符号整数类型:数量与标准有符号整数类型一一对应,除了signed char外直接在前面加关键字unsigned就得到对应的无符号整数类型,比如unsigned short int,不过这点标准文档没直说。

这份最小宽度表格抄自C++标准文档,顺便算了一下它们按照最小宽度能表示的范围的极限,其中long long表示范围比较大采用科学计数法表示。

类型最小宽度N有符号最小值有符号最大值无符号最大值
signed char8-128127256
short16-327683276765536
int16-327683276765536
long32-214748364821474836474294967296
long long64-9.22x10^189.22x10^181.84x10^19

一个具有宽度N的有符号整数类型的取值范围是,大于或等于-2^(N-1),小于或等于2^(N-1)-1;无符号整数类型对应是大于等于0,小于等于2^N

除了上面几个之外,下面这些也是整数类型,但是在标准里被单独罗列:

  • 普通字符类型:char,signed char,unsigned char。其中char类型是特殊的类型,由特定的编译器决定里面实际是signed char或是unsigned char
  • 窄字节字符类型:由普通字符类型和char8_t组成。char8_t隐藏类型是unsigned char
  • char16_tchar32_t,这两个也属于整数类型。(它们隐藏类型是uint_least16_tuint_least32_t,但是这两个隐藏类型不是整数类型)。
  • wchar_t类型。它是特殊的类型,宽字节字符,由特定编译器决定是有符号或者无符号整数,它能表示所有的国际长字节字符。
  • 类型bool,它是由编译器决定的无符号整数类型,取值范围是truefalse。它没有sign,unsigned,short,long这四种前缀。

整数类型示例

#include <iostream>

using namespace std;

int main() {
    int i;
    cout << "输出0到9:" << endl;
    for (i = 0; i < 10; i++) {
        cout << i << " ";
    }
    cout << endl;
    return 0;
}

输出:

输出0到9:
0 1 2 3 4 5 6 7 8 9 

演示bool

#include <iostream>

using namespace std;

int main() {
    char noticeTrue[] = "TRUE";
    char noticeFalse[] = "FALSE";
    bool condition = false;
    if (condition) {
        cout << noticeTrue << endl;
    } else {
        cout << noticeFalse << endl;
    }
    return 0;
}

输出:

$ ./a.out
FALSE

另外,标准规定了整数类型的最小值,最大值是没有限制的,所以实际上获取最小最大值结果可能是:

#include <iostream>

using namespace std;

int main() {
    cout << "type int ~ min=" << numeric_limits<int>::min() << endl;
    cout << "type int ~ max=" << numeric_limits<int>::max() << endl;
    return 0;
}

运行程序:

$ ./a.out
type int ~ min=-2147483648
type int ~ max=2147483647

跟除了C语言之外的其它高级编程语言相比,C++的整数类型比较复杂。在实际用的时候整数一般是用int类型定义,除非长度不够再换更大范围的。名字里面带有char字样的一般是定义成数组,用来存储字符串,UTF8编码的用char8_t,UTF16用char16_t,诸如此类。char类型比较特殊,除了ASCII编码的字符串外,涉及网络传输、文件读写等,需要一块区域做缓存的时候一般用char定义一块连续内存空间。bool用法就是存储真或者假,相当于别的编程语言的布尔类型。

浮点数类型

三种:float,double,long double,这三种中,后面的类型范围大于前面的类型范围。至于具体的范围是多大由具体的编译器决定。可以用std::numeric_limits类获取具体编译器上的最大、最小值(适用于整数、浮点数类型)。

浮点数类型使用示例

#include <iostream>

using namespace std;

int main() {
    float a, b, c;
    a = 1.01;
    b = 3.99;
    c = a * b;
    cout << "c=" << c << endl;
    return 0;
}

运行结果

c=4.0299

获取最大最小值示例(不同的机器上可能结果不一样)

#include <iostream>

using namespace std;

int main() {
    cout << "min=" << numeric_limits<long double>::min() << endl;
    cout << "max=" << numeric_limits<long double>::max() << endl;
    return 0;
}

运行结果

$ ./a.out
min=3.3621e-4932
max=1.18973e+4932

其它类型

除了算术类型之外的两种类型,在C++标准中这两个是单独作为两个类型来说明的。

  • cv void,使用CV限定符(constvolatile)修饰的void——也就是const voidvolatile void的统称,它跟void是不一样的
  • std::nullptr_t。命名空间std里面的nullptr_t类型。

复合类型

笼统地说,C++复合类型包括:

  • 数组
  • 函数
  • 引用
  • 类和结构体
  • 联合体
  • 枚举类型
  • 指针

数组

数组作用是存放相同类型的一组对象。数组声明方式:

类型 名称 [可选的常量表达式] 可选的其它限定符序列

例如下面的fibonacci就是一个数组:

#include <iostream>

using namespace std;

int main() {
    int i;
    int fibonacci[6] = {1, 1};
    cout << "计算前" << endl;
    for (i = 0; i < 6; i++) {
        cout << "i=" << i << ", value=" << fibonacci[i] << endl;
    }
    for (i = 2; i < 6; i++) {
        fibonacci[i] = fibonacci[i - 2] + fibonacci[i - 1];
    }
    cout << "计算后" << endl;
    for (i = 0; i < 6; i++) {
        cout << "i=" << i << ", value=" << fibonacci[i] << endl;
    }
    return 0;
}

运行程序将输出:

计算前
i=0, value=1
i=1, value=1
i=2, value=0
i=3, value=0
i=4, value=0
i=5, value=0
计算后
i=0, value=1
i=1, value=1
i=2, value=2
i=3, value=3
i=4, value=5
i=5, value=8

浮点数数组

#include <iostream>

using namespace std;

int main() {
    float x[] = {1.1, 2.2, 3.3}; // 初始化可以用 {} ,非初始化不能这样用
    for (int i = 0; i < 3; i++) {
        cout << "i=" << i << ", value=" << x[i] << endl;
    }
    return 0;
}

输出:

$ ./a.out
i=0, value=1.1
i=1, value=2.2
i=2, value=3.3

也可以声明多维数组,例如2维:

#include <iostream>

using namespace std;

int main() {
    int matrix[3][4];
    int i, j, n = 0;
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 4; j++) {
            matrix[i][j] = ++n;
        }
    }
    cout << "二维数组的内容:" << endl;
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 4; j++) {
            cout << "matrix(" << i << "," << j << ")=" << matrix[i][j] << "    ";
        }
        cout << endl;
    }
    return 0;
}

输出:

二维数组的内容:
matrix(0,0)=1    matrix(0,1)=2    matrix(0,2)=3    matrix(0,3)=4    
matrix(1,0)=5    matrix(1,1)=6    matrix(1,2)=7    matrix(1,3)=8    
matrix(2,0)=9    matrix(2,1)=10    matrix(2,2)=11    matrix(2,3)=12    

函数

C++中函数是一种类型,函数的名称可以当成变量名称用,能进行一些特定的操作。比如:

#include <iostream>

using namespace std;

int x (int a, int b);

int main() {
    int (*z) (int a, int b);
    z = &x;
    cout << (void *)&x << endl;
    cout << (void *)z << endl;
    cout << (*z)(3, 9) << endl;
    return 0;
}

int x (int a, int b) {
    return a + b;
}

* 运行结果,z保存的地址就是函数x的地址,于是(*z)就是函数x。

0x4008ec
0x4008ec
12

引用

如下,类型名称后面用符号&表示这是对应的引用类型:

#include <iostream>

using namespace std;

int main() {
    int x = 100;
    int& y = x; // y 引用了 x
    cout << "x=" << x << endl;
    cout << "y=" << y << endl; // 读取 y 就是读取 x
    y = 12; // 对 y 赋值就是对 x 赋值
    cout << "x=" << x << endl;
    cout << "y=" << y << endl;
    return 0;
}

输出:

x=100
y=100
x=12
y=12

类和结构体

标准中的描述是:包含一系列各种类型的对象、枚举和用于操纵这些对象的函数,以及对访问这些实体的一些限制。类是一种用途比较复杂的数据类型,这里简单做示例,更多内容单独整理一份文档。下面的class可以无缝替换为struct,它们都可用作定义类的关键字,其功能有点区别但是差不了多少。

#include <iostream>

using namespace std;

class Student {
public:
    Student(float age) {
        this->age = age;
    }
    void sayYourAge() {
        cout << "我今年" << age << "岁了。" << endl;
    }
private:
    float age;
};

int main() {
    Student xiaoMing = Student(14);
    Student xiaoWang = Student(17);
    xiaoMing.sayYourAge();
    xiaoWang.sayYourAge();
    return 0;
}

运行结果:

$ ./a.out
我今年14岁了。
我今年17岁了。

联合体

这里只简单介绍一下C++中的联合体unionunion能够在相同内存空间存储不同类型的对象。具体允许存入怎样的对象可以在定义时声明。在读取union中保存的对象时,按照什么方式读取决于访问成员。这是一个非常特殊的地方,也是联合的特征。另外,同struct一样,联合默认访问权限也是公有的,并且也具有成员函数。

#include <iostream>

using namespace std;

union Exams {
    float average;
    int   score;
    char  level;
};

int main() {
    Exams englishExams;
    englishExams.average = 76.342;
    englishExams.score = 80;
    englishExams.level = 'A'; // 由于union类型里面数据成员是保存进相同的地址,所以后面覆盖前面的,只有'A'是最终存进去的东西
    cout << "average=" << englishExams.average << "    地址:" << (void *)&(englishExams.average) << endl;
    cout << "score=" << englishExams.score << "    地址:" << (void *)&(englishExams.score) << endl;
    cout << "level=" << englishExams.level << "    地址:" << (void *)&(englishExams.level) << endl;
    return 0;
}

* 输出:

average=9.10844e-44    地址:0x7ffd15cee06c
score=65    地址:0x7ffd15cee06c
level=A    地址:0x7ffd15cee06c

枚举类型

枚举类型比较简单,它相当于给按顺序给自定义的常量赋予了自增值,也可以在定义时给需要枚举的常量指定一个值(值可以重复)。不能假设里面对应的值是int或者unsigned int类型,编译器会看情况选择更大范围的类型去存储。

用法:

#include <iostream>

enum Level {
    A = 100,
    B = 80,
    C = 60
};

int main() {
    Level exam = A;
    if (exam == A || exam == B) {
        std::cout << "还可以" << std::endl;
    } else {
        std::cout << "差" << std::endl;
    }
    return 0;
}

运行:

$ ./a.out
还可以

指针

  1. 指向任何对象的指针和指向const volatile voidconst voidvolatile void的指针都属于C++的复合类型。这种对象的类型称为“对象指针类型”,下面例子的a,b,x,y,z都是对象指针类型。
int main() {
    const void *x; // x 是复合类型
    volatile void *y; // y 是复合类型
    const volatile void *z; // z 是复合类型
    int* a; // 指向 int 类型的指针是复合类型
    float* b; // 指向 float 类型的指针是复合类型
    return 0;
}
  1. 具有类型的指向函数(包括类的静态成员)的指针。示例:
#include <iostream>

class Example {
public:
    static void sayHello() {
        std::cout << "你好啊,我是Example类的静态成员函数" << std::endl;
    }
};

void sayHello(); // 在main之前声明函数,当然也可以直接把函数定义在这里,效果相同

int main() {
    /* 声明pointerToSayHello是一个无参数且返回void类型的函数指针,
     * 并初始化其值为sayHello的地址。该函数指针指向的是普通的函数。
     */
    void (*pointerToSayHello)() = &sayHello;
    /* 声明pointerToExampleSayHello是一个无参数且返回void类型的函数指针,
     * 并初始化其值为Example::sayHello的地址。该函数指针指向的是静态成员函数。
     */
    void (*pointerToExampleSayHello)() = &(Example::sayHello);
    // 可以像调用函数一样执行:
    (*pointerToSayHello)();
    (*pointerToExampleSayHello)();
    return 0;
}

void sayHello() {
    std::cout << "你好啊" << std::endl;
}

* 运行的结果是:

$ ./a.out 
你好啊
你好啊,我是Example类的静态成员函数

注:指向对象结尾(如数组结尾)、空指针值或非法指针值的指针也算指针类型。指向cv void或者非cv void的指针可以用来指向不知道是什么类型的对象,这种指针能够容纳任何类型的对象指针,cv void *类型的对象具有跟cv char *类型的对象相同的表示和对齐特性。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值