C++数据类型、变量类型、修饰符类型

1、命名空间

头文件<iostream>

using namespace std; 告诉编译器使用 std 命名空间

1.1 命名空间(namespace)的意思

可能会出现相同命名的类的功能各不相同,在类前面加上 namespace(名字空间) 以示区分。

std::

std 表示是 C++ 的标准命名空间,是 standard(标准)的缩写,就是编译系统自带有的,按 C++ 标准定义好了的。

比如,在使用输出 std::cout 时,如果它达不到我们想要的效果,我们也可以自己定义一个名字空间。取名 myspace,再在这个空间里写一个 cout 函数来实现。调用时,就成了 myspace::cout

1.2 using namespace std;

这个的作用是曝光整个 std 名称空间,使其中的所有成员皆可直接使用。

1、声明了命名空间 std,后续如果有未指定命名空间的符号,那么默认使用 std,这样就可以使用 cin、cout、vector 等。

2、假设你不使用预处理 using namespace std; 就要加上 std::cin 或者 std::cout。

cin 用于从控制台获取用户输入,cout 用于将数据输出到控制台。

输入流对象cin , cout 是输出流对象,

可以用 >> 和 <<,是因为分别在其类中对相应运算符进行了重载。

1.3 标识符命名

C++ 标识符是用来标识变量、函数、类、模块,或任何其他用户自定义项目的名称。


  1. 一个标识符以字母 A-Z 或 a-z 或下划线 _ 开始,后跟零个或多个字母、下划线和数字(0-9)。
  2. C++ 标识符内不允许出现标点字符,比如 @、& 和 %;
  3. C++ 命名是区分大小写
  4. 可以使用带有 $ 的标识符

比如:

有效标识符:mohd zara abc move_name a_123 myname50 _temp j a23b9 retVal

1.4 ::的作用

:: 在 C++ 中表示作用域,和所属关系。 :: 是运算符中等级最高的,它分为三种

1.4.1 作用域符号

作用域符号 :: 的前面一般是类名称,后面一般是该类的成员名称,C++ 为例避免不同的类有名称相同的成员而采用作用域的方式进行区分。

比如:A、B两个类,都有成员data。那么分别表示

A::data表示A的成员data

B::data表示B的成员data

1.4.2 全局作用域符号:

当全局变量在局部函数中与其中某个变量重名,那么就可以用 :: 来区分,例如

cpp 复制代码
char data;
void sleep()
{
    char data = 97;//a的ASCII码
    ::data = 80;//大写字母P的ASCII码
    
    cout << "局部变量:" << data<< endl;
    cout << "全局变量:" << ::data << endl;
}
打印结果:
局部变量:a
全局变量:P

要注意的是使用 cout 输出 char 类型数据 ,打印的数据是对应的ASCII码,而非定义的数值

1.4.3 作用域分解运算符

比如声明了一个类 A,类 A 里声明了一个成员函数 void f(),但没有在类的声明里给出f的定义,那么在类外定义 f 时,就要写成 voidA::f(),表示这个 f() 函数是类 A 的成员函数。例如

cpp 复制代码
class CA 
{
public:
  int ca_var;
  int add(int a, int b);
  int add(int a);
}
//那么在实现这个函数时,必须这样写:
int CA::add(int a, int b)
{
  return a + b;
}
//另外,双冒号也常常用于在类变量内部作为当前类实例的元素进行表示,比如:
int CA::add(int a)
{
  return a + ::ca_var;
}
//表示当前类实例中的变量ca_var。

1.5 "\n" 与 endl 的区别?

\n表示内容为一个回车符的字符串(不刷新缓冲区)

std::endl 输出一个换行符,并立即刷新缓冲区。(刷新缓冲区)

2、数据类型

2.1 基本数据类型

七种基本的数据类型:

|------|--------------------|-----|
| 类型 | 关键字 | 字节数 |
| 布尔型 | bool | 1 |
| 字符型 | char | 1 |
| 整型 | int | 4 |
| 浮点型 | float | 4 |
| 双浮点型 | double | 8 |
| 无类型 | void | |
| 宽字符型 | wchar_t(short int) | 2 |

默认情况下,int、short、long都是带符号的

2.1.1 C++相关函数与头文件

头文件:<limits>

字节大小函数:sizeof(data type);

取值范围函数:numeric_limits<data type>::max(or min)

3、变量

3.1 变量类型

变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头。

大写字母和小写字母是不同的,因为 C++ 是大小写敏感的。

整数类型(Integer Types)

  1. int:用于表示整数,通常占用4个字节。
  2. short:用于表示短整数,通常占用2个字节。
  3. long:用于表示长整数,通常占用4个字节。
  4. long long:用于表示更长的整数,通常占用8个字节。

浮点类型(Floating-Point Types)

  1. float:用于表示单精度浮点数,通常占用4个字节。
  2. double:用于表示双精度浮点数,通常占用8个字节。
  3. long double:用于表示更高精度的浮点数,占用字节数可以根据实现而变化。

字符类型(Character Types)

  1. char:用于表示字符,通常占用1个字节。
  2. wchar_t:用于表示宽字符,通常占用2或4个字节。
  3. char16_t:用于表示16位Unicode字符,占用2个字节。
  4. char32_t:用于表示32位Unicode字符,占用4个字节。

布尔类型(Boolean Type)

bool:用于表示布尔值,只能取true或false。

枚举类型(Enumeration Types)

enum:用于定义一组命名的整数常量。

指针类型(Pointer Types)

type*:用于表示指向类型为type的对象的指针。

数组类型(Array Types)

type[ ]或type[size]:用于表示具有相同类型的元素组成的数组。

结构体类型(Structure Types)

struct:用于定义包含多个不同类型成员的结构。

类类型(Class Types)

class:用于定义具有属性和方法的自定义类型。

共用体类型(Union Types)

union:用于定义一种特殊的数据类型,它可以在相同的内存位置存储不同的数据类型。

3.2 变量自动转换规则

3.1.1 自动转换规则


1、若参与运算量的类型不同,则先转换成同一类型,然后进行运算。

2、转换按数据长度增加的方向进行,以保证精度不降低。

如int 型和long型运算时,先把 int 转成 long 型后再进行运算。
若两种类型的字节数不同,转换成高字节数类型

若两种类型的字节数相同,有符号转换成无符号类型

3、所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算。

4、char型和short型参与运算时,必须先转换成int型。

5、在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型转换为左边量的类型。如果右边量的数据类型长度比左边长时,将丢失一部分数据,这样会降低精度:


cpp 复制代码
int a ;
float b = 1.24;
a = b;
cour << a;
输出:1

3.1.2 强制转换规则

通过类型转换运算实现。

cpp 复制代码
float b =1.24;
int a =2;
cout << a+(int)b << endl;
输出:3

3.3 变量作用域

三个地方可以定义变量:

函数外部----------------全局变量

函数内部/代码块内部---局部变量

函数参数----------------形参
变量有四种作用域:

|-------|------------------------|---------------------------|
| | 范围 | 生命周期 |
| 全局作用域 | 全局变量 可以被 当下文件的任何函数访问 | 程序开始创建---程序结束销毁 |
| 局部作用域 | 函数内部声明的变量 可以被 当下函数内部访问 | 函数每次被调用时被创建,在函数执行完后被销毁。 |
| 块作用域 | 代码块内部声明的变量只能在代码块内部访问 | 代码块每次被执行时被创建,在代码块执行完后被销毁。 |
| 类作用域 | 类内部声明的变量可以被类的所有成员函数访问 | 类作用域变量的生命周期与类的生命周期相同。 |

ps:如果全局变量和局部变量重名,那么局部变量将覆盖全局变量。但是C++可以使用::来引用全局

cpp 复制代码
#include<iostream>
using namespace std;

int a = 10;
int main()
{
    int a = 20;
    cout << ::a << endl;   // 10
    cout << a << endl;     // 20
    return 0;
}

3.3.1 局部变量和全局变量的初始化

定义局部变量系统不会初始化,是随机数。

定义全局变量系统会自动初始化:

4、修饰符类型

|------|------------------------------------------------|-------------------|------|
| 数据类型 | 整形 | 字符型 | 双精度型 |
| 修饰符 | signed、unsigned、long 和 short (可以不写int,int是隐含的) | signed 、 unsigned | long |

4.1 类型限定符(存储类)

|----------|------------------------------------------------------------|
| 限定符 | 含义 |
| const | 常量不能修改 |
| volatile | 易变的变量值,每次编译数值去地址中读(常用于多线程) |
| static | 定义静态变量,作用域仅限当前文件/函数,不能被外部访问 |
| register | 频繁使用的变量,保存在CPU中加速访问提高效率 |
| restrict | 由 restrict 修饰的指针是唯一 一种访问它所指向的对象的方式。 |
| mutable | 表示类中的成员变量可以在 const 成员函数中被修改。 |
| explicit | 修饰只有一个参数的类构造函数,表明该构造函数是显式而非隐式。禁止类对象之间的隐式转换,以及禁止隐式调用拷贝构造函数。 |

5、存储类

存储类 定义 C++ 程序中变量/函数的范围(可见性)和生命周期,放在修饰类型之前。列举常见的:

5.1 auto类

这是默认的存储类说明符,通常可以省略不写。

生命周期:auto 指定的变量具有自动存储期,即它们的生命周期仅限于定义它们的块(block)。auto 变量通常在栈上分配。

用于两种情况:

1、声明变量时根据初始化表达式自动推断该变量的类型(很少使用)

cpp 复制代码
auto f=3.14;      //double
auto s("hello");  //const char*
auto z = new auto(9); // int*
auto x1 = 5, x2 = 5.0, x3='r';//错误,必须是初始化为同一类型

2、 声明函数时函数返回值的占位符。

5.2 register类

用于声明变量,并提示编译器将这些变量存储在寄存器中,以便快速访问。使用 register 关键字可以提高程序的执行速度,因为它减少了对内存的访问次数。

注意:在 C++11 及以后的版本中,register 已经是一个废弃的特性,不再具有实际作用。

5.3 static类

​​​​5.3.1 修饰局部变量

修饰变量在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。

静态局部变量有以下特点:

  • 该变量在全局数据区分配内存;
  • 静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;
  • 静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;
  • 它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束;

​​​​5.3.2 修饰全局变量

static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。

5.3.3 修饰类数据成员

static 用在类数据成员上时,会导致仅有一个该成员的副本被类的所有对象共享。

修饰类的成员变量:

  • 静态成员变量是先于类的对象而存在
  • 这个类的所有对象共用一个静态成员
  • 如果静态成员是公有的,那么可以直接通过类名调用
  • 静态成员数据在声明时候类外初始化

static 修饰类的成员方法:

  • 静态成员函数是先于类的对象而存在
  • 可用类名直接调用(公有)
  • 在静态成员函数中没有this指针,所以不能使用非静态成员

5.4 extern类

extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。(很常用)

5.5 const类

1、 const修饰常量:

const修饰的常量代替宏定义: const double PI = 3.1415;

2、 const修饰成员变量:

cpp 复制代码
const int data;

const 修饰的成员变量必须在构造方法的参数列表初始化,不能在构造函数内部进行赋值操作

const 修饰的成员变量不能被修改。

3、 const修饰成员方法:

cpp 复制代码
void showData()const{ }

const 修饰的成员函数中不能修改成员变量,不能调用非 const 修饰的函数。

5.5.1 const 相比 #define 的优点:

const 常量有数据类型,而 #define 没有,编译器可以对const进行类型安全检查,而对define只能进行字符替换,没有安全检查,并且在字符替换时候可能导致意想不到的错误。

有些集成化的调试工具可以对 const 常量进行调试,但是不能对宏常量进行调试。

5.5.2 const char*, char const*的区别

从右向左读

cpp 复制代码
char  * const cp; ( * 读成 pointer to ) 
cp is a const pointer to char (cp是一个常量指针指向char)
指向的对象可变,指针的指向不可变

const char * p(char const * p); 
p is a pointer to const char; (cp是一个指针指向常量char)
指向的对象只读,指针的指向可变

const 放在 * 的左侧任意位置,限定了该指针指向的对象是只读的;
const放在 * 的右侧,限定了指针本身是只读的,即不可变的。
const 右边修饰谁,就说明谁是不可变的。

​​​​​​​5.6 thread_local类

**作用:**可以将 thread_local 仅应用于数据声明和定义,thread_local 不能用于函数声明或定义。使用 thread_local 说明符声明的变量仅可在它创建的线程上访问。

**周期:**变量在创建线程时创建,并在销毁线程时销毁。 每个线程都有其自己的变量副本。

thread_local 说明符可以与 static 或 extern 合并。

cpp 复制代码
thread_local int x;  // 命名空间下的全局变量
class X
{
    static thread_local std::string s; // 类的static成员变量
};
static thread_local std::string X::s;  // X::s 是需要定义的
 
void foo()
{
    thread_local std::vector<int> v;  // 本地变量
}

学习文章:菜鸟C++ 教程 | 菜鸟教程 (runoob.com)

相关推荐
海岛日记8 分钟前
centos一键卸载docker脚本
linux·docker·centos
AttackingLin1 小时前
2024强网杯--babyheap house of apple2解法
linux·开发语言·python
Ysjt | 深1 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
ephemerals__1 小时前
【c++丨STL】list模拟实现(附源码)
开发语言·c++·list
Microsoft Word2 小时前
c++基础语法
开发语言·c++·算法
学Linux的语莫2 小时前
Ansible使用简介和基础使用
linux·运维·服务器·nginx·云计算·ansible
一只小小汤圆2 小时前
opencascade源码学习之BRepOffsetAPI包 -BRepOffsetAPI_DraftAngle
c++·学习·opencascade
踏雪Vernon2 小时前
[OpenHarmony5.0][Docker][环境]OpenHarmony5.0 Docker编译环境镜像下载以及使用方式
linux·docker·容器·harmonyos
学Linux的语莫2 小时前
搭建服务器VPN,Linux客户端连接WireGuard,Windows客户端连接WireGuard
linux·运维·服务器