关键字 | 作用 |
---|---|
override | 覆盖,如果派生类在虚函数声明时使用了override关键字,该函数必须重载基类(父类)中的同名函数。 |
inline | 内联函数,把函数指定为内联函数,解决频繁调用的函数消耗大量的栈空间(栈内存)的问题。 |
基本的内置类型:
布尔型:
bool
字符型:
char
整型:
int
浮点型:
float
双浮点型:
double
无类型:
void
宽字符型:
wchar_t
【本质:typedef short int wchar_t;】
类型修饰符:
signed
、unsigned
、short
、long
;默认情况下,
int
、short
、long
都是带符号的,即signed int
、signed short
、signed long
;
typedef 声明
给数据类型关键字重命名。
语法:
typedef type newname;
例:
typedef int money; money minghave = 100; // 声明整型变量minghave初始值为100
枚举类型
枚举是c++的派生数据类型,如果一个变量只有几种可能的值,可以定义为枚举类型。枚举就是将变量的值一个一个的列举出来,该变量的值只能在列举出来的值范围内。
关键字:
enum
语法:
enum 枚举名{标识符[=整型常数],标识符[=整型常数],...标识符[=整型常数] } 枚举变量;
示例:
enum color {red,green,blue} c; c = blue;
默认情况下,第一个名称值为0,第二个名称的值为1,第三个为2,以此类推。也可以给名称赋予一个特殊的值,只需要添加一个初始值即可。
示例:
enum color {red,green=5,red}; // ****green赋值为5之后,red为6,默认情况每个名称的值比前一个大1,red依然为0.
类型转换
四种类型转换方式:1、静态转换;2、动态转换;3、常量转换;4、重新解释转换。
静态转换(Static Cast)——强制类型转换
不进行任何运行时的类型检查,因此可能会导致运行时错误。
int i = 10; float f = static_cast<float>(i);//将int转换为float
动态转换(Dynamic Cast)
运行时进行类型检查,不能转换则返回空指针或引发异常。
// 动态转换通常用于将一个 基类指针或引用 转换为 派生类指针或引用。 class Base {}; class Derived : public Base {}; Base* ptr_base = new Derived; Derived* ptr_derived = dynamic_cast<Derived*>(ptr_base);// 将基类指针转换为派生类指针。
常量转换(Const Cast)
用于将const类型的对象转换为非const类型的对象。
常量转换只能用于转换掉const的属性,不能改变对象的类型。
const int i = 10; int& r = const_cast<int&>(i);// 常量转换,将const int 转换为int
重新解释转换(Reinterpret Cast)
将一个数据类型的值重新解释为另一个数据类型的值,通常用于在不同的数据类型之间的转换。
重新解释转换不进行任何检查,因此可能会导致未定义的行为。
int i = 10; float f = reinterpret_cast<float&>(i);// 将int类型转换为float
在声明变量时,不带初始化的定义:带有静态存储持续时间的变量会被隐式初始化为NULL(所有字节的值都是0),其他所有变量的初始值是未定义的。
bool
、char
、 int
、float
、 double
、 void
、 wchar_t
。
在函数或一个代码块内部声明的变量,称为局部变量
#include<iostream>
using namespace std;
int main(){int a, b; // 局部变量声明a = 10;b = 20; // 变量初始化cout<<a<<b<<endl;return 0;
}
在函数参数的定义中声明的变量,成为形式参数
在所有函数外部声明的变量,成为全局变量
#include<iostream>
using namespace std;int g = 20;int main(){int g = 10;cout<< g << endl; // 10,局部变量的值覆盖全局变量的值。return 0;
}
局部作用域:在函数内部声明的变量具有局部作用域,它们只能在函数内部访问。局部变量在函数每次被调用时被创建,在函数执行完后被销毁。
全局作用域:在所有函数和代码块之外声明的变量具有全局作用域,它们可以被程序中的任何函数访问。全局变量在程序开始时被创建,在程序结束时被销毁。
块作用域:在代码块内部声明的变量,它们只能在代码块内部访问。块作用域变量在代码块每次被执行时被创建,在代码块执行完后被销毁。
类作用域:在类内部声明的变量具有类作用域,它们可以被类的所有成员函数访问。类作用域变量的生命周期与类的生命周期相同。
#include<iostream>class MyClass {public:static int class_var; // 类作用域变量
};
int MyClass::class_var = 30;
int main(){std::cout << "类变量:"<<MyClass::class_var<<std::endl;return 0; // 输出为:类变量:30
}
整数常量
前缀为 0x
或 0X
表示十六进制, 0
表示八进制,不带前缀默认表示为十进制。
整数常量后缀:U
表示无符号整数(unsigned), L
表示长整数(long),后缀可以大写或者小写,U和L顺序任意。
212 // 合法
215u // 合法
0xFeeL // 合法
078 // 非法,8不是八进制数字
032UU // 非法,不能重复后缀
85 // 十进制
0213 // 八进制
0x4b // 十六进制
30 // 整数,十进制
30u // 无符号整数
30l // 长整数
30lu // 无符号长整数
浮点常量
浮点常量有整数部分、小数点、小数部分和指数部分组成,可以使用小数形式或者指数形式表示浮点常量。
布尔常量
true
代表真,false
代表假。
字符常量
字符常量是括在单引号
中的。
当常量以 L
(仅大写)开头,则表示是一个宽
字符常量(例:L'a'
),此时它必须存储在 wchar_t
类型的变量中。否则,它是一个窄
字符常量,此时它可以存储在 char
类型的简单变量中。
字符常量可以是一个普通的字符(例:'x'
)、一个转义字符(例:'t'
)或者一个通用的字符(例:'u02C0'
)
一些特定的字符:
转义序列 | 含义 |
---|---|
\ | 字符 |
' | '字符 |
" | "字符 |
? | ?字符 |
a | 警报铃声 |
b | 退格键 |
f | 换页符 |
n | 换行符 |
r | 回车 |
t | 水平制表符 |
v | 垂直制表符 |
ooo | 一到三位的八进制数 |
一个或多个数字的十六进制数 |
#include<iostream>
using namespace std;int main(){cout<<"hellotworldnn"<<"哇"<<endl;return 0;
}
字符串常量
字符串字面值或常量时括在双引号 ""
中的。一个字符串包含类似于字符常量的字符:普通的字符、转义序列和通用的字符。
可以使用 做分隔符,把一个很长的字符串常量进行分行。
#include<iostream>
#include<string>
using namespace std;int main(){string greeting = "hello,c++";cout<<greeting;cout<<"n";string greeting2 = "hello,c++";cout<<greeting2<<endl;return 0;
}
// 运行结果相同。
常量的定义
c++编程的良好习惯:将常量定义为大写字母形式
在 c++
中有两种定义常量的方式;
#define
预处理器const
关键字#define 预处理器
// 语法
#define identifier value
示例:
#include<iostream>
using namespace std;
#define HEIGHT 10
#define WIDTH 5
#define NEWLINE 'n'
int main(){int area;area = HEIGHT * WIDTH;cout<<"面积:"<<NEWLINE<<area<<endl;return 0;
}
运行结果
面积:
50
const关键字
// 语法
const type variable = value;
// 示例
const int WIDTH = 5;
const int HEIGHT = 10;
const char NEWLINE = 'n';
c++允许在char、int和double数据类型前放置修饰符。
signed
:表示变量可以存储负数。对于整型变量来说,signed可以省略,整型变量默认为有符号类型。
unsigned
:表示变量不能存储负数。
short
:变量范围比int
更小。short int
可缩写为short
long
:变量范围比int
更大。long int
可缩写为long
long long
:变量范围比long
更大,c++11新增的数据类型修饰符
float
:单精度浮点数
double
:双精度浮点数
bool
:布尔类型,只有true
和false
两个值
char
:表示字符类型
wchar_t
:表示宽字符类型,可以存储Unicode
字符
当signed、unsigned、long和short简写时,代表为int类型,int时隐含的。
signed、unsigned、long和short可应用于整型,
signed、unsigned可应用与字符型,
long可用于双精度型。
signed、unsigned、long 和short 可以组合使用。
无符号整数和有符号整数的差别,示例:
#include<iostream>
using namespace std;
int main(){short int i; // 有符号短整数short unsigned int j; // 无符号短整数j = 50000;i = j;cout << i << "t" << j << endl;return 0;
}
// 结果为
// -15536 50000
//计算过程为:50000转为二进制数为:1100 0011 0101 0000,
// 最左边 1 表示负号,计算机以补码形式来表示数字,要得到原数字,先-1再取反,
// 得:0011 1100 1011 0000,即:-15536
const:const
定义常量,表示该常量不能被修改。
const int NUM = 10; // 定义常量NUM,值不能修改
const int* ptr = &NUM; // 定义指向常量的指针,指针所指的值不可修改
int const* ptr2 = &NUM; // 和上一行等价
volatile:表示定义的变量可能会被程序以外的因素改变,如硬件或其他线程。
volatile int num = 20; //定义变量num,值可能会在位置时间被改变
restrict:由 restrict
修饰的指针是唯一 一种访问它所指向的对象的方式。只有C99增加了该限定符
mutable:表示类中的成员变量可以在 const 成员函数中被修改。
class Example {public:int get_value() const {return value_; // const 关键字表示该成员函数不会修改对象中的数据成员。}void set_value(int value) const {value_ = value; // mutable 关键字允许在 const 成员函数中修改成员变量}private:mutable int value_;
}
static:用于定义静态变量,表示该变量的作用域仅限于当前文件或当前函数内,不会被其他文件或函数访问。
void example_function(){static int count = 0; // static 使变量 count 存储在程序生命周期内都存在。count++;
}
register:用于定义寄存器变量,表示该变量被频繁使用,可以存储在CPU的寄存器中,以提高程序的运行效率。
void example_function(register int num) {// register 关键字建议编译器将变量 num 存储在寄存器中// 以提高程序执行速度// 但是实际上是否会存储在寄存器中,由编译器决定
}
存储类定义C++程序中变量/函数的范围(可见性)和生命周期。这些说明符放在它们所修饰的类型之前。下面列出C++程序中可用的存储类
auto
:从C++17开始,auto关键字不再是C++存储类的说明符
C++11开始,auto用于声明变量时根据初始化表达式自动推断变量的数据类型、声明函数时函数返回值的占位符。
C++98标准中auto关键字用于自动变量的声明,使用极少多余在C++17中删除
auto f = 3.14; // double
auto s("hello"); // const char*
auto z = new auto(9); // int*
auto x1 = 5, x2 = 3.0, x3 = 'a'; // 错误用法,初始化应为同一种数据类型
register
:在C++17中,register关键字被弃用。
register存储类用于定义存储在寄存器中而不是RAM中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个词),且不能对它应用一元的
'&'
运算符(因为没有内存位置)。
{register int miles;
}
static
:
static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。
static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。
在 C++ 中,当 static 用在类数据成员上时,会导致仅有一个该成员的副本被类的所有对象共享。
extern
:extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候
extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用 ‘extern’ 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。
当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。
mutable
:
mutable 说明符仅适用于类的对象。它允许对象的成员替代常量,即mutable 成员可以通过 const 成员函数修改。
thread_local(C++11)
:
使用 thread_local 说明符声明的变量仅可在它在其上创建的线程上访问。 变量在创建线程时创建,并在销毁线程时销毁。 每个线程都有其自己的变量副本。
thread_local 说明符可以与 static 或 extern 合并。
可以将 thread_local 仅应用于数据声明和定义,thread_local 不能用于函数声明或定义。
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; // 本地变量
}
算术运算符
+
:相加
-
:相减
*
:相乘
/
:相除
%
:取模运算符,整除后的余数
++
:自增运算符,加1
--
:自减运算符,减1
关系运算符
==
:检查两个操作数的值是否相等,相等为真,不等为假
!=
:检查两个操作数的值是否不等,不等为真,相等为假
>
:大于
<
:小于
>=
:大于等于
<=
:小于等于
逻辑运算符
&&
:逻辑与运算,两个操作数同为真,则为真;有假则假。
||
:逻辑或运算,两个操作数同为假,则为假;有真则真。
!
:逻辑非运算,改变逻辑状态。
位运算符
&
:按位与运算,有0为0,同1为1。
|
:按位或运算,有1为1,同0为0。
^
:按位异或运算,相同为0,不同为1。
~
:取反运算符,例: 60取反过程为: 60: 0011 1100(正数原码、补码) 所有位取反: 1100 0011(负数的补码) 减一变反码: 1100 0010(负数的反码) 数值位取反: 1011 1101(负数的原码)
<<
:二进制左移运算符,将运算对象的所有二进制位全部左移n位,最左边二进制位丢弃,最右边二进制位补0。例: 60 << 2; // 左移两位 过程为:0011 1100=》1111 0000
>>
:二进制右移运算符,将运算对象的二进制位全部右移n位,正数最左边补0,负数最左边补1,最右边丢弃。例: 60 >> 3; // 右移三位 过程为:0011 1100 =》0000 0111
赋值运算符
=
:将右边操作数的值赋给左边操作数。
+=
:将右边操作数的值加上左边操作数的值赋值给左边操作数。
-=
:将左边操作数的值减去右边操作数的值的结果赋值给左边操作数。
*=
:将右边操作数与左边操作数相乘的结果赋值给左边操作数。
/=
:将左边操作数与右边操作数相除的结果赋值给左边操作数。
%=
:将左右两边的操作数取模运算后的结果赋值给左边操作数。
<<=
:左移赋值。
>>=
:右移赋值。
&=
:按位与赋值。
|=
:按位或赋值。
^=
:按位异或赋值。
杂项运算符
sizeof
:返回变量的大小,类似字节数。
? :
:三目运算符(条件运算符)。
,
:逗号运算符。
.
和->
:成员运算符,用于引用类、结构和共用体的成员。强制转换运算符:例:
(int)2.34
,结果为2
。
&
:指针运算符,返回变量的地址,例:&a,返回变量a的实际地址(内存地址)。
*
:指针运算符,指向一个变量。
运算符优先级
后缀 > 一元 > 乘除 > 加减 > 移位 > 关系 > 相等 > 位与运算 > 位异或 > 位或 > 逻辑与 > 逻辑异或 > 逻辑或 > 三目运算符 > 赋值运算符 > 逗号运算符
while
循环:for
循环:break
continue
goto
if
语句:if
语句:switch
语句:...?...:...
函数的声明与定义。
*Lambda函数与表达式:也称匿名函数、Lambda表达式。
Lambda函数,把函数看作对象,可以像对象一样使用,比如可以将它们赋值给变量或作为参数传递,还可以像函数一样对其求值。
例:
// 语法: [capture](parameters)->return-type{body} // 示例1 [](int x, int y){ return x< y; } // 示例2 [](int x, int y)->int { int z = x + y; return z + x; }
在Lambda函数中,可以访问当前作用域的变量,这是Lambda函数的
闭包
(Closure)行为,与JavaScript闭包不同,c++变量传递有传值和传引用的区别,可以通过[]
来指定。
C++数学运算:
使用C++内置的数学函数,需要引用头文件 <cmath>
。
cos(double)
:余弦函数,double型
sin(double)
:正弦函数,double型
tan(double)
:正切函数,double型
log(double)
:对数函数,double型
pow(double, double)
:pow(x, y),求x的y次方
hypot(double, double)
:hypot(x, y),求 x2 + y2 的平方根,类似求直角三角形的斜边长。
sqrt(double)
:返回参数的平方根
abs(int)
:返回整数的绝对值
fabs(double)
:返回任意一个浮点数的绝对值。经过测试,abs() 也可以返回浮点数的绝对值。
floor(double)
:向下取整floor(12.3234); // 12 floor(12.9999); // 12 floor(-12.00012); // -13 floor(-12.999); // 13
c++随机数:
使用函数
rand()
,使用之前需要先调用srand()
函数。
#include<iostream>
#include<ctime>
#include<cstdlib>
using namespace std;
int main(){int i, j;srand((unsigned)time(NULL));for(i=0;i<10;i++){j = rand();cout<<"随机数:"<<j<<endl;}return 0;
}
语法:
type arrayName[arraySize];
示例:
// 声明 int nums[10];// 初始化 int nums[4] = { 3, 2, 5, 8 }; // 正确 int numbers[3] = { 1, 4, 2, 3 }; // 错误初始化,初始化的元素长度为4,声明的数组长度为3,个数不能超过3。 int ages[] = { 19, 18, 22}; // 正确初始化,数组未规定长度,长度以实际初始化长度为准。
多维数组
示例:
// 二维整型数组 int twodim[3][2] = {{1,2},{3,4},{5,6}}; int a[3][2] = {1,2,3,4,5,6}; // 以上两种初始化等同,内嵌的括号可选。// 三维整型数组 int threedim[4][2][3];
指向数组的指针
示例:
double a[10]; double *p = a;
解释:
以上声明的双精度型数组
a
,是一个指向&a[0]
的指针,即数组 a 的第一个元素的地址,因此上面把 p 赋值为 数组 a 的第一个元素的地址。// 以下等价 *p = a[0]; *(p+1) = a[1] = *(a+1); *(p+2) = a[2] = *(a+2); ......
传递数组给函数
c++传数组给函数,会把数据类型自动转换为指针类型,因此实际传的是地址。
语法:
// 方式一 void myFunction(int *param){} // 方式二 void myFunction(int param[3]){} // 方式三 void myFunction(int param[]){}
从函数返回数组
c++不允许返回一个完整的数组作为函数的参数,但是,可以通过指定的不带索引的数组名来返回一个数组的指针。
如果想要从函数返回一个一维数组,则必须声明函数为指针类型。
示例:
int* myFuncion(){}
不能简单地返回指向局部数组的指针,因为当函数结束时,局部数组将被销毁,指向它的指针将变得无效。
C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static 变量。
为了避免以上情况,可以使用静态数组或者动态分配数组。
实例:使用静态数组#include<iostream> #include<cstdlib> #include<ctime>using namespace std;int* getRandom(){static int r[10];srand((unsigned)time(NULL));for(int i=0;i<10;i++){r[i] = rand();cout<<r[i]<<endl;}return r;} int main(){int *p;p = getRandom();for(int i = 0;i<10;i++){cout<<"*(p+"<<i<<"):";cout<<*(p+i)<<endl;}return 0;}
实例:使用动态分配数组
使用动态分配数组需要在函数内部使用 new 运算符来分配一个数组,并在函数结束时使用 delete 运算符释放该数组
#include <iostream> using namespace std;int* createArray(int size) {int* arr = new int[size];for (int i = 0; i < size; i++) {arr[i] = i + 1;}return arr;}int main() {int* myArray = createArray(5);for (int i = 0; i < 5; i++) {cout << myArray[i] << " ";}cout << endl;delete[] myArray; // 释放内存return 0;}
c++的字符串,在末尾存储了一个空字符