简述
C++大概有如下关键字
。其中主要分类为:指定符、运算符、内联汇编符、本文将对下面的关键字进行分析
A字母
auto
auto(C++98)
C++98标准中就存在了auto关键字,那时的auto用于声明变量为自动变量,自动变量意为拥有自动的生命期。
int a = 0; // 自动分配内存空间
auto int a = 0; //自动分配内存空间
在C++89 auto感觉有点脱裤子放屁的感觉。没什么用处,存在感低
auto(C++11)
C++98中的auto多余且极少使用,C++11已经删除了这一用法,取而代之的是全新的auto:变量的自动类型推断.本质是一个占位符。
占位符就是先占住一个固定的位置,等着你再往里面添加内容的符号,广泛用于计算机中各类文档的编辑。格式占位符(%)是在C/C++语言中格式输入函数,如 scanf、printf 等函数中使用。其意义就是起到格式占位的意思,表示在该位置有输入或者输出。
用法:专一的变量声明
没有出现auto之前,操作标准库时经常需要这样
#include<string>
#include<vector>
int main()
{
std::vector<std::string> vs;
for (std::vector<std::string>::iterator i = vs.begin(); i != vs.end(); i++)
{
}
}
而C++11,后利用auto的用法可以简化为以下代码,可阅读性立马提升了。
#include<string>
#include<vector>
int main()
{
std::vector<std::string> vs;
for (auto i = vs.begin(); i != vs.end(); i++)
{
}
}
类模板时用auto
若不使用auto变量来声明v,那这个函数就难定义啦,不到编译的时候,谁知道x*y的真正类型是什么呢?
template <typename _Tx,typename _Ty>
void Multiply(_Tx x, _Ty y)
{
auto v = x*y;
std::cout << v;
}
/************************函数返回值也可以用*********************/
template <typename _Tx, typename _Ty>
auto multiply(_Tx x, _Ty y)->decltype(x*y)
{
return x*y;
}
注意事项
- const 、int& 等修饰的数据如果要atuo 只用会的该变量的数据类型,要获得修饰需加上 “&”
- auto 是占位符,不能用于函数或者模板的输入参数,不能用siozf(auto)、typeid(auto).
auto关键字做类型自动推导时,依次施加一下规则:如果初始化表达式是引用,则去除引用语义。简单来说就是atuo加上"&"不会改变之前额语义。
int a = 10;
int &b = a;
auto c = b;//c的类型为int而非int&(去除引用)
auto &d = b;//此时c的类型才为int&
c = 100;//a =10;
d = 100;//a =100;
如果初始化表达式为const或volatile(或者两者兼有),则除去const/volatile语义,如果auto关键字带上&号,则不去除const语意
const int a1 = 10;
auto b1= a1; //b1的类型为int而非const int(去除const)
const auto c1 = a1;//此时c1的类型为const int
b1 = 100;//合法
c1 = 100;//非法
const int a2 = 10;
auto &b2 = a2;//因为auto带上&,故不去除const,b2类型为const int
b2 = 10; //非法
auto同样也适合在数组中使用
int a7[3] = { 1, 2, 3 };
auto & b7 = a7;
cout << typeid(b7).name() << endl; // typeid 为输出变量的数据类型
// 程序输出为:int[3]
int a7[3] = { 1, 2, 3 };
auto & b7 = a7;
cout << typeid(b7).name() << endl;
// 程序输出为: int *
函数或者模板参数不能被声明为auto,auto并不是一个真正的类型。auto仅仅是一个占位符,它并不是一个真正的类型,不能使用一些以类型为操作数的操作符,如sizeof或者typeid。
void func(auto a) //错误
{
//...
}
cout << sizeof(auto) << endl;//错误
cout << typeid(auto).name() << endl;//错误
【扩展】register (C++11)[c++17后弃用]
register关键字请求编译器尽可能的将变量存在CPU内部寄存器中,而不是通过内存寻址访问,以提高效率。注意是尽可能,不是绝对。register变量必须是能够被CPU所接受的类型。这通常意味着register变量必须是一个单个的值,并且长度应该小于或者等于整型的长度。不过,有些机器的寄存器也能存放浮点数。因为register变量可能不存放在内存中,所以不能用”&“来获取register变量的地址。
#include<stdio.h>
int main()
{
register int a=10;
printf("%p\n",&a);
return 0;
}
&操作编译会报错
alignas[C++11开始使用]
alignas关键字用来设置内存中对齐方式,最小是8字节对齐,可以是16,32,64,128等。
补充
在32位单片机上,以下是常见数据类型所占用的空间大小:
- 1字节:char、unsigned char
- 2字节:short、unsigned short
- 4字节:int,unsigned int,float,指针,long
- 8字节:double
#include <iostream>
using namespace std;
struct struct_Test1
{
char c;
int i;
double d;
};
struct alignas(8) struct_Test2
{
char c;
int i;
double d;
};
struct alignas(16) struct_Test3
{
char c;
int i;
double d;
};
struct alignas(32) struct_Test4
{
char c;
int i;
double d;
};
int _tmain(int argc, _TCHAR* argv[])
{
struct_Test1 test1;
struct_Test2 test2;
struct_Test3 test3;
struct_Test4 test4;
cout<<"char size:"<<sizeof(char)<<endl;
cout<<"int size:"<<sizeof(int)<<endl;
cout<<"double size:"<<sizeof(double)<<endl;
cout<<"test1 size:"<<sizeof(test1)<<endl;
cout<<"test2 size:"<<sizeof(test2)<<endl;
cout<<"test3 size:"<<sizeof(test3)<<endl;
cout<<"test4 size:"<<sizeof(test4)<<endl;
system("pause");
return 0;
输出结果
test1 理论上是占据13字节的,由于alignas关键字的修饰会讲其按照8字节对齐,所以这里的test1的大小为16字节。
alignof[C++11起]
含义 :用于获取类型的对齐字节数。与alignas搭配使用
注意事项
关于alignof格外要注意的一点是,它只能用于操作类型,不能操作变量。sizeof则不同,既可以操作类型,也可以操作变量。
alignas只能往大对齐,不能往小对齐,如果类型本身的对齐依据是4,那么alignas(2)则不起效!即它不能起到#pragma pack的作用!如果想往小对齐,只能使用pragma pack。
struct A
{
int a;
int b;
A()
{
cout << "alignof(int) = " << alignof(int) << endl;
cout << "alignof(b) = " << alignof(b) << endl; //编译错误!alignof只能操作类型,不能操作变量!
cout << "sizeof(int) = " << sizeof(int) << endl;
cout << "sizeof(b) = " << sizeof(b) << endl; //OK!sizeof既能操作类型,也能操作变量!
}
}
and
含义
用作 && 的替用
#include <iostream>
int n;
int main()
{
if(n > 0 and n < 5)
{
std::cout << "n is small and positive\n";
}
}
and_eq
含义
用作 &= 的替用
#include <iostream>
#include <bitset>
int main()
{
std::bitset<4> mask("1100");
std::bitset<4> val("0111");
val and_eq mask;
std::cout << val << '\n';
}
输出:0100
asm
含义
asm(指令字符串):在C++中嵌入汇编代码的时候需要用asm关键字
作用
汇编指令由字符串方式填在括号里,括号里能填一条或者多条汇编指令,有些编译器会把嵌入的汇编指令单独放在一个文件里编译。
#include <stdio.h>
nt main()
{
asm ("nop");
printf("hello");
asm ("nop nop "
"nop");
return 0;
}
B字母
bitand
含义
用作 & 的替用,表示按位与 &
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
int a = 1;
int b = 0;
int c = a bitand b;
printf("c value %d",c);
system("pause");
return 0;
}
//输出:c value 0
bitor
含义
用作 | 的替用,表示按位与 |
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
int a = 1;
int b = 0;
int c = a bitor b;
printf("c value %d",c);
system("pause");
return 1;
}
//输出:c value 1
bool
含义
C++中的bool关键字是用于定义布尔类型的变量,其只有两个取值,即true和false。bool类型在C++中通常用于逻辑判断和条件控制语句中。
用法
使用bool类型的变量进行逻辑判断:
bool flag = true;
if (flag) {
// 如果flag为true,则执行以下代码
cout << "flag为true" << endl;
} else {
// 如果flag为false,则执行以下代码
cout << "flag为false" << endl;
}
使用bool类型的变量作为函数的返回值:
bool isPrime(int n) {
if (n <= 1) {
return false;
}
for (int i = 2; i <= sqrt(n); i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
使用bool类型的变量作为循环条件:
bool flag = true;
while (flag) {
// 循环体
flag = false; // 设置循环结束条件
}
break
含义
在C++中,break关键字用于在循环语句中立即停止执行循环,跳出循环体。break只能用于for、while、do-while和switch语句中。
当在循环语句中使用break时,程序将立即跳出循环体,不再进行循环体内后续的操作,直接执行后面的语句。
用法
使用break退出for循环
for(int i=0;i<10;i++){
if(i==5){
break;
}
cout<<i<<endl;
}
在上面的代码中,当i等于5时,break语句被执行,程序将退出循环体,不再输出后续的数字。
使用break退出while循环
int i=0;
while(i<10){
if(i==5){
break;
}
cout<<i<<endl;
i++;
}
在上面的代码中,当i等于5时,break语句被执行,程序将退出循环体,不再输出后续的数字。
使用break退出switch语句
int x = 2;
switch (x) {
case 1:
cout << "x is 1" << endl;
break;
case 2:
cout << "x is 2" << endl;
break;
case 3:
cout << "x is 3" << endl;
break;
default:
cout << "x is not 1, 2 or 3" << endl;
break;
}
在上面的代码中,当x等于2时,第二个case语句被执行,break语句被执行,程序将跳出switch语句,不再执行后续的case语句。
C字母
case[与switch结合使用]
switch(1)
{
case 1 : cout << '1'; // 打印 "1",
case 2 : cout << '2'; // 然后打印 "2"
}
catch[try-catch]
含义
catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。通常与try结合使用
#include <iostream>
using namespace std;
double division(int a, int b)
{
if( b == 0 )
{
throw "Division by zero condition!";
}
return (a/b);
}
int main ()
{
int x = 50;
int y = 0;
double z = 0;
try
{
z = division(x, y);
cout << z << endl;
}
catch (const char* msg)
{
cerr << msg << endl;
}
return 0;
}
//输出:Division by zero condition!
char
含义
字符类型,占据1字节[8位]
#include <stdio.h>
int main()
{
char *pstr;
// 也可以 char * TAG = "hellow"
pstr = new char[20];
pstr[0] = 'a';
pstr[1] = 'b';
pstr[2] = 'c';
pstr[3] = '/';
pstr[4] = '0';
pstr[5] = '1';
pstr[6] = '2';
pstr[7] = '3';
pstr[8] = ' ';
pstr[9] = '%';
pstr[10] = 'd';
pstr[11] = '\n';
pstr[12] = 0;
int c;
c = 0;
while(c < 13)
{
printf("%d\n" , pstr[c]);
c = c+1;
}
printf(pstr , 99);
printf("\n");
return 0;
}
char8_t、char16_t、char32_t[C++11起]
含义
字符类型,char16_t[占16位]、char32_t[占32位]
对于 UTF-8 编码方法而言,只能表示256个字符,世界上有那么多国家,每个国家都有一些特俗的符号要表示。显然普通类型似乎是无法满足需求的,毕竟普通类型无法表达变长的内存空间。所以一般情况下我们直接使用基本类型 char 进行处理,而过去也没有一个针对 UTF-16 和 UTF-32 的字符类型。
到了 C++11,char16_t 和 char32_t 的出现打破了这个尴尬的局面。除此之外,C++11 标准还为 3 种编码提供了新前缀用于声明 3 种编码字符和字符串的字面量,它们分别是 UTF-8 的前缀 u8、UTF-16 的前缀 u 和 UTF-32 的前缀 U:由于字符类型增多,因此我们还需要了解一下字符串连接的规则:如果两个字符串字面量具有相同的前缀,则生成的连接字符串字面量也具有该前缀,如下表所示。
char ch1{ 'a' }; // or { u8'a' }
wchar_t ch2{ L'a' };
char16_t ch3{ u'a' };
char32_t ch4{ U'a' };
char utf8c = u8'a'; // C++17标准
//char utf8c = u8'好';
char16_t utf16c = u'好';
char32_t utf32c = U'好';
char utf8[] = u8"你好世界";
char16_t utf16[] = u"你好世界";
char32_t utf32[] = U"你好世界";
class[C++11起]
含义
定义一个类
在模板声明中, class 可用于引入类型模板形参与模板模板形参
class Foo; // 类的前置声明
class Bar // 类的定义
{
public:
Bar(int i) : m_i(i) {}
private:
int m_i;
};
template <class T> // 模板参数
void qux()
{
T t;
}
int main()
{
Bar Bar(1);
class Bar Bar2(2); // 详细类型
}
co_await、co_return、co_yield
compl
含义
"~"的替用,位取反操作。
#include <iostream>
using namespace std;
int main() {
int x = 10;
int y = ~x;
cout << "x = " << x << endl;
cout << "y = " << y << endl;
return 0;
}
//输出:x = 10
// y = -11
concept[C++20]
含义
Concept C++ 是一种 C++20 中的新特性,它允许程序员定义一组限制条件,以确保模板实参满足特定的约束条件。这样可以使得模板更加灵活,同时也可以提高程序的可读性和可维护性。
用法
约束模板参数类型:可以使用 Concept C++ 来定义模板参数类型必须满足的条件,从而避免模板实例化时出现意外的错误
template <typename T>
concept Integer = std::is_integral_v<T>;
template <Integer T>
void print(T value) {
std::cout << value << std::endl;
}
int main() {
print(42); // OK
print("foo"); // error: concept constraint 'Integer' was not satisfied for template argument 'const char *'
}
在上面的代码中,我们定义了一个名为 Integer
的 Concept,它要求模板参数类型必须是整数类型。在 print
函数中,我们使用了 Integer
来约束模板参数类型,从而避免了传入非整数类型的参数。
约束模板参数值:可以使用 Concept C++ 来定义模板参数值必须满足的条件,从而避免模板实例化时出现意外的错误
template <typename T>
concept Positive = requires(T value)
{
{ value > 0 } -> std::same_as<bool>;
};
template <Positive T>
void print(T value)
{
std::cout << value << std::endl;
}
int main()
{
print(42); // OK
print(-1); // error: concept constraint 'Positive' was not satisfied for template argument '-1'
print("foo"); // error: no matching function for call to 'print(const char [4])'
}
在上面的代码中,我们定义了一个名为 Positive
的 Concept,它要求模板参数值必须是大于 0 的数字。在 print
函数中,我们使用了 Positive
来约束模板参数值,从而避免了传入不符合条件的参数。
const
含义
const关键字用来定义常量,其作用是告诉编译器该变量的值不能被修改。const int和int const都表示一个整型常量,它们的区别在于const int是将整型变量声明为常量,而int const是将指向整型的指针声明为常量,即不能通过该指针修改变量的值。
用法
const int a = 10;
int const *p = &a;
在这个例子中,a是一个整型常量,不能被修改;而p是一个指向整型常量的指针,也不能通过p修改a的值。如果将p声明为int * const,则p本身成为常量,指向的变量可以被修改,但不能指向其他变量。
const_cast
含义
const_cast是C++中的一个类型转换操作符,可以用于去除const或volatile属性,从而允许对被const或volatile限定的变量进行修改。
用法
const_cast<type>(expression);
//其中,type是要转换的类型,expression是要转换的表达式。
去除const属性
const int a = 10;
int& b = const_cast<int&>(a);
b = 20;
std::cout << a << std::endl; // 输出10
std::cout << b << std::endl; // 输出20
上述代码中,我们定义了一个const int类型的变量a,并将其赋值为10。然后使用const_cast将a转换为int&类型的变量b,并将其赋值为20。由于const_cast去除了a的const属性,因此b可以修改a的值。最后输出a和b的值,可以看到a的值没有改变,而b的值变成了20。
去除volatile属性
volatile int c = 30;
int& d = const_cast<int&>(c);
d = 40;
std::cout << c << std::endl; // 输出40
std::cout << d << std::endl; // 输出40
上述代码中,我们定义了一个volatile int类型的变量c,并将其赋值为30。然后使用const_cast将c转换为int&类型的变量d,并将其赋值为40。由于const_cast去除了c的volatile属性,因此d可以修改c的值。最后输出c和d的值,可以看到它们的值都变成了40。
注意事项
const_cast只能用于去除const或volatile属性,并且只能用于指针或引用类型的变量。如果将const_cast用于非指针或引用类型的变量,则会导致编译错误。此外,使用const_cast需要慎重,因为去除const或volatile属性可能会导致程序出现未定义的行为。
constexpr
含义
C++中的constexpr关键字用于在编译时求值的常量表达式,可以用于声明常量、函数等。constexpr变量必须在编译时初始化,而且其值在编译期间就已经确定,因此程序运行时不再需要计算
用法
声明一个constexpr常量
constexpr int x = 5;
声明一个constexpr函数
constexpr int add(int a, int b)
{
return a + b;
}
使用constexpr函数
constexpr int a = 2;
constexpr int b = 3;
int c = add(a, b); // c的值为5
使用if constexpr
if constexpr (sizeof(int) == 4)
{
// 32位系统
}
else
{
// 64位系统
}
注意事项
使用constexpr时需要确保表达式是常量表达式,否则会导致编译错误。
continue
含义
continue是一个关键字,它用于跳过当前循环中的剩余代码,并继续执行下一次循环。当某个条件满足时,使用continue语句可以忽略当前循环中的某些代码,从而达到节省时间和资源的效果。
for (int i = 0; i < 10; i++)
{
if (i == 5)
{
continue; // 跳过i等于5时的代码
}
cout << i << endl;
}
/*
输出结果:
1
3
5
7
9
*/
D字母
decltype
含义
decltype是C++11中引入的关键字,用于获取表达式的数据类型。。
用法
确定表达式的数据类型,而不用实际执行表达式
int x = 10;
double d = 3.14;
decltype(x + d) result; // result的类型为double,因为x + d的结果是double类型
decltype还可以用于获取函数返回值的类型
int foo();
double bar();
decltype(foo()) x; // x的类型为int,因为foo()返回int类型
decltype(bar()) y; // y的类型为double,因为bar()返回double类型
decltype还可以用于获取类中成员变量的类型
class MyClass
{
public:
int x;
double y;
};
MyClass obj;
decltype(obj.x) a; // a的类型为int
decltype(obj.y) b; // b的类型为double
default
含义
用法
默认值:default可以用于为变量或函数参数设置默认值,当调用函数时不传递该参数时,将使用默认值
int add(int a, int b = 0)
{
return a + b;
}
int result = add(1); // result = 1
result = add(1, 2); // result = 3
在上面的代码中,b参数设置了默认值0。因此,当调用add函数时,可以只传递一个参数,第二个参数将使用默认值0:
switch语句中的默认情况.在switch语句中使用default关键字可以指定一个默认情况,当没有任何一个case语句匹配时执行该情况
int num = 1;
switch(num)
{
case 1:
cout << "One" << endl;
break;
case 2:
cout << "Two" << endl;
break;
default:
cout << "Other" << endl;
break;
}
在上面的代码中,num为1,因此执行第一个case语句。如果num为其他值,则执行default情况。
另外,default关键字还可以用于自定义类型的构造函数中,用于指定默认构造函数
delete
含义
C++中的delete关键字用于释放动态分配的内存,即由new操作符创建的对象或数组在不再需要时必须通过delete操作符来释放它们占用的内存。delete操作符会执行以下操作
用法
删除单个对象
int *ptr = new int; // 动态分配一个整数变量
*ptr = 100; // 对变量进行赋值
delete ptr; // 释放内存空间
删除数组
int *arr = new int[10]; // 动态分配一个包含10个整数的数组
delete[] arr; // 释放内存空间
删除对象数组
class MyClass {
public:
MyClass() {}
~MyClass() {}
};
MyClass *objs = new MyClass[5]; // 动态分配一个包含5个MyClass对象的数组
delete[] objs; // 释放内存空间
do
含义
do {
// 循环体代码
} while (循环条件);
do关键字用于实现循环结构,即do-while循环,do-while循环与while循环的区别在于,do-while循环会先执行一次循环体代码,然后再进行条件判断,如果条件成立,则继续执行循环体,否则跳出循环
用法
计算1~10的和
int sum = 0;
int i = 1;
do {
sum += i;
i++;
} while (i <= 10);
cout << "1+2+3+...+10=" << sum << endl
判断用户输入的密码是否正确
string password;
do {
cout << "请输入密码:";
cin >> password;
} while (password != "123456");
cout << "密码正确!" << endl;
执行一次循环体
int count = 0;
do {
cout << "执行了一次循环体!" << endl;
count++;
} while (count < 1);
double
含义
double是用来声明双精度浮点数类型的关键字。它可以存储比float更大的数字范围,通常被用来存储需要高精度的浮点数值,例如科学计算、金融计算等
用法
声明一个双精度浮点数变量并初始化
double num = 3.14159265358979323846;
使用double变量进行数学运算:
double x = 2.5;
double y = 1.2;
double z = x + y; // z的值为3.7
将double类型的值强制转换为其他类型:
double num = 3.14;
int x = (int) num; // x的值为3
float y = (float) num; // y的值为3.14
dynamic_cast
含义
dynamic_cast是C++中用于动态类型转换的关键字,它可以将一个指向基类对象的指针或引用,转换为指向派生类对象的指针或引用。这个转换在运行时进行,而不是在编译时确定。
用法
举例来说,假设有一个Animal类和一个Dog类,Dog是Animal的派生类。我们可以用dynamic_cast将Animal类型的指针或引用转换为Dog类型的指针或引用,如下所示:
Animal* animal = new Dog();
Dog* dog = dynamic_cast<Dog*>(animal);
如果animal指向的实际是一个Dog对象,那么这个转换就会成功,dog指向这个对象。但如果animal指向的实际是另一个派生自Animal的类的对象,那么转换就会失败,dog将指向空指针。
另一个例子是,假设有一个Shape类和两个派生类Circle和Rectangle,我们希望将一个指向Shape对象的指针或引用,转换为指向Circle或Rectangle对象的指针或引用。这个转换可以用dynamic_cast实现
Shape* shape = new Circle();
Circle* circle = dynamic_cast<Circle*>(shape);
if(circle != nullptr) {
// 转换成功,circle指向Circle对象
}
else {
// 转换失败,shape指向的实际是另一个类型的对象
}
注意事项
dynamic_cast只能用于指向类层次结构中的指针或引用。如果我们试图将一个非指针或引用类型的对象进行dynamic_cast转换,将会导致编译错误
字母E
else
含义
else是C++中的关键字,用于在if语句中,当if条件不成立时执行的代码块。else语句必须紧跟if语句,并且if语句必须包含一条语句或代码块
用法
if-else语句
int score = 85;
if (score > 90)
{
cout << "优秀" << endl;
} else {
cout << "良好" << endl;
}
//上述代码中,如果分数大于90,则输出“优秀”,否则输出“良好”
if-else if-else语句
int num = 3;
if (num == 1) {
cout << "星期一" << endl;
} else if (num == 2) {
cout << "星期二" << endl;
} else if (num == 3) {
cout << "星期三" << endl;
} else {
cout << "输入错误" << endl;
}
//上述代码中,根据输入的数字输出对应的星期几,如果输入的数字不在1~7之间,则输出“输入错误”。
嵌套if-else语句:
int num1 = 10, num2 = 20;
if (num1 > 0) {
if (num2 > 0) {
cout << "两个数都大于0" << endl;
} else {
cout << "num2小于等于0" << endl;
}
} else {
cout << "num1小于等于0" << endl;
}
//上述代码中,当num1和num2都大于0时输出“两个数都大于0”,当num1小于等于0时输出“num1小于等于0”,当num2小于等于0时输出“num2小于等于0”
enum
含义
enum 是 C++ 语言中的关键字,用于定义枚举类型。枚举类型是一种用户自定义的数据类型,它可以让程序员定义一组具有代表性的常量,这些常量可以在程序中使用.enum 定义的枚举类型可以具有一个或多个枚举常量。枚举常量是被定义为枚举类型中的常量值。枚举常量的值默认是从 0 开始依次递增的,但也可以手动指定枚举常量的值。
用法
以下是一些 C++ 中使用 enum 的例子:
enum Color {
RED,
GREEN,
BLUE
};
// 定义了一个枚举类型 Color,其中包含三个枚举常量:RED, GREEN, BLUE
enum Size {
SMALL = 1,
MEDIUM = 5,
LARGE = 10
};
// 定义了一个枚举类型 Size,其中包含三个枚举常量:SMALL=1, MEDIUM=5, LARGE=10
enum Weekday {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
};
// 定义了一个枚举类型 Weekday,其中包含七个枚举常量:MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
在上面的例子中,我们可以使用枚举类型来表示颜色、大小和星期几等常量。枚举类型不仅可以使代码更加清晰易懂,还可以提高代码的可读性和可维护性。
explicit
含义
在C++中,explicit关键字用于禁止隐式类型转换,只允许显式类型转换。当我们使用某个类的构造函数进行类型转换时,如果构造函数前加上explicit关键字,那么就只能使用显式类型转换进行转换,否则会报错。
用法
class A {
public:
explicit A(int n) : num(n) {}
private:
int num;
};
void func(A a) {
// do something
}
int main() {
A a1 = 10; // 编译错误,不能使用隐式类型转换
A a2(10); // 正常,使用显式类型转换
func(10); // 编译错误,不能使用隐式类型转换
func(A(10)); // 正常,使用显式类型转换
return 0;
}
在上面的例子中,我们定义了一个类A,它的构造函数前加上了explicit关键字,这就限制了我们不能使用隐式类型转换。在main函数中,我们尝试使用隐式类型转换,但是都会导致编译错误。只有在使用显式类型转换的情况下,才能正常进行类型转换。
class B {
public:
B(int n) : num(n) {}
operator int() const { return num; }
private:
int num;
};
void func(int n) {
// do something
}
int main() {
B b(10);
func(b); // 正常,使用隐式类型转换
func(static_cast<int>(b)); // 正常,使用显式类型转换
return 0;
}
在上面的例子中,我们定义了一个类B,并且重载了int类型的类型转换运算符。在main函数中,我们尝试使用隐式类型转换将B类型的对象传递给func函数,这时会自动调用B类中的int类型转换运算符,将B类型转换为int类型。但是如果我们在B类的构造函数前加上了explicit关键字,那么就只能使用显式类型转换才能将B类型转换为int类型。
export[C++20]
含义
export 关键字是 C++20 新增的一种语法特性,它的作用是将模板定义导出为独立的实体,使得在不同的编译单元中可以使用该模板定义,而不必将其放在头文件中。模板必须被定义在头文件中,因为编译器需要在编译时将模板实例化,而头文件可以被多个编译单元包含,从而实现模板在不同编译单元中的使用。但这种方式会导致头文件变得很大,增加编译时间和链接时间,同时也可能导致模板的代码泄露。
用法
export 关键字,可以将模板定义导出为独立的实体,使得不同编译单元可以共享该模板定义
// 文件 a.cpp
export template<typename T>
void print(T value) {
std::cout << value << std::endl;
}
// 文件 b.cpp
import void print(int);
int main() {
print(42); // 调用 a.cpp 中的 print 函数
return 0;
}
在上面的例子中,a.cpp 中导出了一个 print 模板函数的定义,b.cpp 中使用 import 关键字导入了该定义,从而可以在 b.cpp 中使用 print 函数。
// 文件 a.cpp
export template<typename T>
class Vector {
public:
Vector(int size) : size_(size), data_(new T[size_]) {}
~Vector() { delete[] data_; }
// ...
private:
int size_;
T* data_;
};
// 文件 b.cpp
import Vector<int>;
int main() {
Vector<int> v(10); // 调用 a.cpp 中的 Vector 类模板
return 0;
}
在上面的例子中,a.cpp 中导出了一个 Vector 类模板的定义,b.cpp 中使用 import 关键字导入了该定义,从而可以在 b.cpp 中使用 Vector 类模板。
注意事项
export 关键字只能用于模板定义,不能用于函数或类的定义,而且 export 的语法还在不断改进中,未来可能会有变化。
extern
含义
extern是一个关键字,用于指示一个变量或函数是在其他文件或模块中定义的。它可以用于在一个文件中声明一个变量或函数,该变量或函数实际上在另一个文件中定义。这个关键字的作用是告诉编译器,该变量或函数在其他文件中定义,编译器在编译时不会生成该变量或函数的代码,而是在链接时将其与其他文件中的定义结合起来。
用法
如果在一个C++程序中,有一个函数或变量在另一个文件中定义,那么可以在当前文件中使用extern关键字进行声明,如下所示:
// file1.cpp
int global_var = 42;
// file2.cpp
extern int global_var; // 声明 global_var 是在另一个文件中定义的变量
int main() {
// 使用 global_var 变量
std::cout << "global_var = " << global_var << std::endl;
return 0;
}
在这个例子中,global_var变量在file1.cpp文件中定义,而在file2.cpp文件中使用。在file2.cpp文件中使用extern关键字声明global_var,这样编译器就知道该变量在其他文件中定义,编译器在编译时不会生成该变量的代码,而是在链接时将其与其他文件中的定义结合起来。
除了变量,extern关键字也可以用于函数的声明。例如:
// file1.cpp
int add(int a, int b) {
return a + b;
}
// file2.cpp
extern int add(int a, int b); // 声明 add 函数是在另一个文件中定义的函数
int main() {
int result = add(2, 3);
std::cout << "result = " << result << std::endl;
return 0;
}
在这个例子中,global_var变量在file1.cpp文件中定义,而在file2.cpp文件中使用。在file2.cpp文件中使用extern关键字声明global_var,这样编译器就知道该变量在其他文件中定义,编译器在编译时不会生成该变量的代码,而是在链接时将其与其他文件中的定义结合起来。
总之,extern关键字是用于指示一个变量或函数是在其他文件或模块中定义的,在C++中它是非常有用的,可以让我们在不同的文件中使用同一个变量或函数。
字母F
false
含义
false是一个关键字,表示“假”或“错误”的布尔值。它是一个预定义的常量,其值为0。false关键字通常用于布尔表达式中,用于表示一个条件不成立或一个函数返回一个错误状态。
用法
使用false关键字检查条件是否不成立:
if (x > y)
{
// do something
}
else
{
// do something else
}
使用false关键字表示函数返回一个错误状态
bool myFunction()
{
// do something
if (error)
{
return false;
}
else
{
return true;
}
}
使用false关键字初始化布尔变量
bool myBool = false;
final[C++11]
含义
在C++中,final关键字用于声明一个类或成员函数不能被继承或重写。使用final关键字修饰的类不能被其他类继承,使用final关键字修饰的成员函数不能被子类重写。
用法
保证类的不可继承性:使用final关键字修饰的类不能被继承。这样可以防止其他类对该类的修改和继承,保证该类的稳定性和安全性
class final_class final {
public:
// ...
};
保证函数的不可重写性:使用final关键字修饰的成员函数不能被子类重写。这样可以保证该函数的不变性和稳定性,防止子类对该函数的误操作和改变。
class Base {
public:
virtual void foo() final;
};
class Derived : public Base {
public:
void foo() override; // 编译错误
};
提高程序性能:使用final关键字可以让编译器在编译时进行优化,提高程序的性能。
class final_class final {
public:
void final_func() final;
};
class Derived : public final_class {
public:
// 编译错误
};
class Base {
public:
virtual void foo() final;
};
class Derived : public Base {
public:
void foo() override; // 编译错误
};
float
含义
float是一种基本数据类型,用于表示单精度浮点数。它可以存储小数点后6-7位数字,通常用于处理需要高精度的浮点数运算。
用法
定义单精度浮点变量:使用float关键字可以定义一个单精度浮点数变量,例如
float f = 3.14;
进行浮点数运算:float类型可以进行基本的加减乘除等浮点数运算,例如:
float a = 1.5, b = 2.5;
float c = a + b;
在函数中传递参数:在函数定义时,可以将float类型的变量作为参数传递给函数,例如:
void foo(float f) {
// do something
}
输出浮点数:使用cout语句可以输出float类型的变量,例如:
float f = 3.14;
cout << f << endl;
for
含义
for关键字是一种循环结构,可以重复执行一段代码块,直到满足指定的条件为止。for循环通常用于遍历数组或执行一定次数的循环操作。
用法
for (初始化表达式; 循环条件; 迭代表达式)
{
// 代码块
}
其中,初始化表达式只会在循环开始之前执行一次,通常用于初始化计数器或声明变量。循环条件是一个布尔表达式,每次循环都会判断该表达式的值是否为真,如果为假,则结束循环。迭代表达式则在每次循环结束后执行,通常用于更新计数器或变量的值。
遍历数组
int arr[] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++)
{
cout << arr[i] << " ";
}
//输出结果:1 2 3 4 5
计算1到10的和
int sum = 0;
for (int i = 1; i <= 10; i++)
{
sum += i;
}
cout << sum << endl;
//输出结果:55
打印乘法口诀表
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= i; j++)
{
cout << i << "*" << j << "=" << i * j << " ";
}
cout << endl;
}
输出结果:
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
friend
含义
friend关键字用于定义类的友元函数或友元类,它允许非成员函数或非该类成员函数访问类的私有成员变量和成员函数。友元函数可以是全局函数、类的成员函数或其他类的成员函数,而友元类则可以访问该类的所有成员。
用法
友元函数的声明通常在类的定义中进行,但是它们的实现需要在类的外部进行。友元函数的定义与普通函数的定义非常相似,只是在函数名称前添加了friend关键字和类名称。例如:
class MyClass {
private:
int private_var;
public:
void public_func();
friend void friend_func(MyClass obj);
};
void friend_func(MyClass obj) {
obj.private_var = 10;
}
在上面的例子中,friend_func函数被声明为MyClass类的友元函数。在函数内部,我们可以直接访问MyClass类的私有成员变量private_var并对其进行修改
除了友元函数以外,我们还可以使用friend关键字定义友元类。例如:
class MyClass {
private:
int private_var;
friend class FriendClass;
};
class FriendClass {
public:
void func(MyClass obj) {
obj.private_var = 10;
}
};
在上面的例子中,FriendClass类被声明为MyClass类的友元类。因此,FriendClass类的成员函数func可以访问MyClass类的私有成员变量private_var并对其进行修改
总之,friend关键字提供了一种灵活的方式来授权非成员函数或非该类成员函数访问类的私有成员变量和成员函数,但是应该谨慎使用,以避免破坏类的封装性和安全性。
字母G
goto
含义
goto关键字用于无条件地转移到程序中的另一个标记。它可以在程序中的任何位置使用,但是通常不建议过度使用,因为它会使代码难以理解和维护。
用法
使用goto语句时,需要在程序中标记要跳转的位置。标记是用标识符和冒号(:)定义的,如下所示:
label:// code
要使用goto跳转到标记处,只需使用以下语法:
goto label;
使用goto跳出多层循环
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (i == 5 && j == 5) {
goto end;
}
}
}
end:
// code
在这个例子中,如果someCondition满足,程序将跳转到标记error处,处理错误。总的来说,虽然goto语句有其用处,但是过度使用会使程序难以维护和理解。在大多数情况下,使用结构化控制语句(如if语句和循环语句)更容易理解和维护。
I字母
if
含义
if关键字用于控制程序的流程,根据条件是否成立来执行不同的代码块。if关键字后面的括号内是一个条件表达式,如果该表达式的值为真,就会执行if后面的代码块;如果该表达式的值为假,就会跳过if后面的代码块,继续执行后面的代码。
用法
判断一个数是否为正数,如果是,则输出“这是一个正数”
int num = -5;
if (num > 0) {
cout << "这是一个正数" << endl;
}
根据用户输入的分数,判断他是否及格,如果及格则输出“恭喜你,及格了!”
int score;
cout << "请输入你的分数:" << endl;
cin >> score;
if (score >= 60) {
cout << "恭喜你,及格了!" << endl;
}
判断用户输入的年份是否为闰年,如果是,则输出“这是一个闰年”
int year;
cout << "请输入一个年份:" << endl;
cin >> year;
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
cout << "这是一个闰年" << endl;
}
inline[C++17]
含义
inline关键字用来告诉编译器将函数的代码直接嵌入到调用函数的位置,而不是像普通函数一样需要在运行时进行函数调用。这样可以减少函数调用的开销,并提高程序的执行效率。inline关键字一般用于短小的函数,而对于较长的函数则不适合使用。
用法
简单的加法函数
inline int add(int a, int b) {
return a + b;
}
用于计算圆的面积的函数
inline double circleArea(double radius) {
return 3.14 * radius * radius;
}
注意事项
inline关键字只是一个建议,编译器并不一定会将函数进行内联优化。
在头文件中使用inline函数时,需要在函数定义之前加上inline关键字,并且在头文件中声明函数
如果函数过于复杂,编译器可能会忽略inline关键字,将函数编译成普通函数进行调用。
int
含义
int关键字表示整数类型,用于声明整数变量或函数返回值。int类型的变量可以存储32位的有符号整数,其取值范围为-2147483648到2147483647。
用法
声明一个int类型的变量:
int x = 5;
声明一个函数返回值为int类型:
int add(int a, int b) {
return a + b;
}
使用int类型进行算术运算:
int a = 10;
int b = 5;
int c = a + b; // c的值为15
从输入流中读取int类型的数据:
#include <iostream>
using namespace std;
int main() {
int x;
cin >> x;
cout << "输入的数字是:" << x << endl;
return 0;
}
字母L
L
含义
long关键字通常用于声明长整型变量,表示一个更大的整数范围。long类型的变量通常占用4个字节的内存空间,可以存储的整数范围为-2,147,483,648到2,147,483,647。如果需要存储更大的整数,可以使用long long类型。
用法
声明一个long类型的变量:
long num = 1234567890;
将一个整数转换为long类型:
int num = 1234567890;
long numLong = (long)num;
将两个long类型的变量相加:
long num1 = 1234567890;
long num2 = 9876543210;
long sum = num1 + num2;
M字母
mutable
含义
mutable关键字用于修饰类的成员变量,表示这个变量可以在const成员函数中被修改。在const成员函数中,所有非静态成员变量都是只读的,但如果用mutable关键字修饰了某个成员变量,则该变量可以在const成员函数中被修改。
用法
缓存计算结果
假设我们有一个计算结果非常耗时的函数,但结果不会改变,我们可以使用mutable关键字来缓存结果,避免重复计算:
class ExpensiveFunc {
public:
int getResult() const {
if (!resultCached) {
// 计算结果
result = calculateResult();
resultCached = true;
}
return result;
}
private:
int result;
mutable bool resultCached = false;
int calculateResult() const {
// 一些非常耗时的计算过程
}
};
在上面的例子中,getResult()函数是一个const成员函数,但它可以修改resultCached变量,以缓存计算结果。
保护数据完整性
有时候我们希望某些成员变量在对象被创建时被初始化,但之后不能被修改。这时我们可以使用mutable关键字来实现:
class Foo {
public:
Foo(int x) : x(x) {}
int getX() const {
return x;
}
private:
const int x;
mutable bool initialized = false;
};
在上面的例子中,x是一个const成员变量,它只能在构造函数中被初始化,之后不能被修改。但我们可以使用initialized变量来记录x是否已经被初始化过,以保护数据完整性。
实现缓存机制
有时候我们希望某个函数的返回值在第一次调用时被计算,之后可以被直接返回。这时我们可以使用mutable关键字来实现缓存机制:
class Bar {
public:
int getResult() const {
if (!resultCached) {
// 计算结果
result = calculateResult();
resultCached = true;
}
return result;
}
void clearCache() {
resultCached = false;
}
private:
mutable int result;
mutable bool resultCached = false;
int calculateResult() const {
// 一些非常耗时的计算过程
}
};
在上面的例子中,getResult()函数在第一次被调用时会计算结果,并将结果缓存到result变量中。之后再次调用该函数时,直接返回缓存的结果。如果我们希望重新计算结果,可以调用clearCache()函数清除缓存。
N字母
do
含义
namespace是C++中用来解决命名冲突的机制,其作用是将一系列的函数、类、变量等封装在一个命名空间内,从而避免与其他命名空间中的同名函数、类、变量等发生冲突。
举个例子,如果我们在开发一个程序时,需要使用一个名为“list”的函数,但是在标准库中也有一个名为“list”的函数,这时就会发生命名冲突。这时候我们可以使用命名空间来避免冲突:
用法
#include <iostream>
#include <list>
namespace myspace
{
void list()
{
std::cout << "This is my list function!" << std::endl;
}
}
int main()
{
myspace::list(); // 调用myspace命名空间中的list函数
std::list<int> lst; // 调用标准库中的list函数
return 0;
}
在上面的例子中,我们使用了一个名为“myspace”的命名空间,并在其中定义了一个名为“list”的函数。当我们想要调用这个函数时,需要在函数名前面加上命名空间名,即“myspace::list()”。这样就能避免与标准库中的list函数发生冲突。
#include <iostream>
namespace myspace
{
namespace sub_space
{
void func()
{
std::cout << "This is a function in sub_space!" << std::endl;
}
}
}
int main()
{
myspace::sub_space::func();
return 0;
}
在上面的例子中,我们定义了一个名为“myspace”的命名空间和一个名为“sub_space”的子命名空间,并在其中定义了一个名为“func”的函数。当我们想要调用这个函数时,需要在函数名前面加上命名空间名和子命名空间名,即“myspace::sub_space::func()”。
new
含义
new关键字用于动态分配内存空间,即在程序运行时根据需要申请内存空间,而不是在编译时就确定了大小。使用new关键字可以返回一个指向新分配内存的指针,方便程序进行操作。
用法
举个例子,假设我们需要在程序中创建一个动态数组。使用new关键字可以这样实现:
int size = 10;
int* myArray = new int[size]; // 动态分配一个大小为10的整型数组
另一个例子是我们需要在程序中创建一个动态的对象。使用new关键字可以这样实现:
class MyClass {
// 类定义
};
MyClass* myObject = new MyClass(); // 动态分配一个MyClass对象
注意事项
delete[] myArray; // 释放动态分配的整型数组内存
delete myObject; // 释放动态分配的MyClass对象内存
需要注意的是,使用new关键字动态分配内存后,需要使用delete关键字释放这些内存空间,否则会导致内存泄漏。可以使用delete关键字这样释放上述两个例子中分配的内存空间
noexcept
含义
noexcept是C++11中新增的关键字,用于指明函数是否会抛出异常。当函数声明为noexcept时,编译器会认为该函数不会抛出任何异常,从而可以进行一些优化,提高程序的性能。
用法
不会抛出异常的函数
int add(int a, int b) noexcept {
return a + b;
}
会抛出异常的函数
void divide(int a, int b) noexcept(false) {
if (b == 0) {
throw "Divide by zero exception";
}
return a / b;
}
在模板编程中使用noexcept
template <typename T>
void swap(T& a, T& b) noexcept(noexcept(a.swap(b))) {
a.swap(b);
}
not
含义
not是一个逻辑运算符,用于求一个表达式的反值。not关键字是一元运算符,接收一个bool类型的操作数,如果操作数为true,则返回false,否则返回true。
用法
not关键字通常用于条件判断语句中,例如if语句或while循环语句,用于判断某个条件是否为假。以下是not关键字的几个示例:
例子1:
bool flag = true;
if (not flag) {
// 如果flag为false,则执行该代码块
}
在这个示例中,如果flag为true,则not flag的结果为false,if语句的代码块不会被执行。如果flag为false,则not flag的结果为true,if语句的代码块会被执行。
例子2:
int num = 10;
while (not num == 0) {
// 如果num不等于0,则执行该代码块
num--;
}
在这个示例中,not num == 0的结果为true,只要num不等于0,while循环的代码块就会被执行。每次循环结束后,num的值会减1,直到num等于0为止。
例子3:
bool result = not (1 > 2);
在这个示例中,1 > 2的结果为false,not false的结果为true,将结果赋值给result变量。result的值为true。
do
含义
not_eq是一个C++关键字,表示不等于运算符。not_eq用于比较两个值是否不相等,返回一个bool类型的值true或false,表示两个值是否不相等。not_eq通常用于条件语句中,例如if语句、while语句等。not_eq的操作对象可以是任意类型的数据,包括基本类型和自定义类型。
用法
以下是not_eq关键字的几个例子:
比较两个整数是否不相等
int a = 10;
int b = 20;
if(a not_eq b){
cout << "a不等于b" << endl;
}
比较两个浮点数是否不相等
float c = 1.23;
float d = 4.56;
if(c not_eq d){
cout << "c不等于d" << endl;
}
比较两个字符串是否不相等
string str1 = "hello";
string str2 = "world";
if(str1 not_eq str2){
cout << "str1不等于str2" << endl;
}
比较两个自定义类型是否不相等
class Student{
public:
int id;
string name;
bool operator not_eq (const Student& other) const{
return this->id not_eq other.id;
}
};
Student stu1{1, "张三"};
Student stu2{2, "李四"};
if(stu1 not_eq stu2){
cout << "stu1不等于stu2" << endl;
}
在上述例子中,not_eq关键字都用于比较两个值是否不相等。如果两个值不相等,则执行if语句中的代码块,输出相应的信息。
nullptr[C++11]
含义
C++11中新增了一个关键字nullptr,用来代替NULL或0,用于表示空指针。
用法
可以避免NULL或0在语义上的二义性。NULL或0既可以表示指针类型的空指针,也可以表示整型的零值,而nullptr只能表示指针类型的空指针
在函数重载时,nullptr可以明确指出参数类型,避免了参数类型不明确的问题。
下面是几个使用nullptr的例子:
指针初始化
int* ptr = nullptr;
函数参数
void foo(int* ptr);
void foo(char* ptr);
foo(nullptr); // 调用foo(int*)函数
判断指针是否为空
if(ptr == nullptr){
// 指针为空
}
模板参数推断
template<typename T>
void foo(T* ptr);
foo(nullptr); // 推断出T为指针类型
总之,nullptr是C++11中一个非常有用的关键字,可以避免程序中空指针的一些常见问题,提高程序的健壮性和可读性。
O字母
operator
含义
operator 是一个关键字,用于定义运算符的重载函数。它的作用就是让我们可以自定义类的行为,让它们能够像内置类型一样支持各种运算符的操作。
用法
举个例子,我们可以通过重载 operator+ 函数来实现两个自定义类对象的相加操作。下面是一个简单的例子:
class MyInt {
public:
MyInt(int value) : value_(value) {}
// 重载加法运算符
MyInt operator+(const MyInt& other) const {
return MyInt(value_ + other.value_);
}
private:
int value_;
};
int main() {
MyInt a(1);
MyInt b(2);
MyInt c = a + b; // 调用 operator+ 函数
return 0;
}
在这个例子中,我们定义了一个 MyInt 类,它有一个 int 类型的成员变量 value_,以及一个重载的 operator+ 函数。这个函数接受另一个 MyInt 类型的参数 other,并返回一个新的 MyInt 对象,其值为两个对象的 value_ 之和。
除了 operator+,C++ 还支持许多其他的运算符重载,比如 operator-、operator*、operator/ 等等。我们可以根据需要自定义这些运算符的行为,让我们的类具有更强的灵活性和可扩展性。
or
含义
or是一个逻辑运算符,用于判断两个条件中是否至少有一个为真。当两个条件中有一个为真时,or运算符返回true,否则返回false。
用法
用于逻辑表达式
int a = 10;
int b = 20;
if(a == 10 or b == 30){
//代码块
}
在上面的代码中,or关键字用于判断两个条件中是否至少有一个为真。如果a等于10或者b等于30,那么条件为真,代码块将会被执行。
用于位运算
在C++中,or运算符也可以用于位运算。对于两个二进制数的对应位,只要有一个为1,那么结果位就为1。例如
int a = 5; //二进制表示为0101
int b = 3; //二进制表示为0011
int c = a | b; //二进制为0111,转为十进制为7
在上面的代码中,or运算符用于对a和b进行位运算,得到的结果为7。
综上所述,or关键字是一个用于逻辑运算和位运算的关键字,用于判断两个条件中是否至少有一个为真。
or_eq
含义
or_eq是C++中的一个位运算符,它用于将左操作数按位或上右操作数,并将结果赋值给左操作数。它等价于“|=”运算符。or_eq关键字可以用于任何整数类型,包括char、short、int、long和long long。
用法
将一个变量的值与另一个变量按位或,并将结果赋值给第一个变量:
int a = 0b1010; //10的二进制表示
int b = 0b1100; //12的二进制表示
a or_eq b; //将a与b按位或,结果为14(二进制为0b1110)
cout << a; //输出14
将一个变量的值与一个常量按位或,并将结果赋值给该变量:
unsigned char c = 0b0010; //2的二进制表示
c or_eq 0b0100; //将c与4按位或,结果为6(二进制为0b0110)
cout << (int)c; //输出6
将一个变量的值与一个表达式按位或,并将结果赋值给该变量:
unsigned int d = 0x1234; //十六进制数0x1234
d or_eq (1 << 8); //将d与256(即1<<8)按位或,结果为0x1334
cout << hex << d; //输出0x1334
or_eq
含义
or_eq是C++中的一个位运算符,它用于将左操作数按位或上右操作数,并将结果赋值给左操作数。它等价于“|=”运算符。or_eq关键字可以用于任何整数类型,包括char、short、int、long和long long。
用法
将一个变量的值与另一个变量按位或,并将结果赋值给第一个变量:
int a = 0b1010; //10的二进制表示
int b = 0b1100; //12的二进制表示
a or_eq b; //将a与b按位或,结果为14(二进制为0b1110)
cout << a; //输出14
将一个变量的值与一个常量按位或,并将结果赋值给该变量:
unsigned char c = 0b0010; //2的二进制表示
c or_eq 0b0100; //将c与4按位或,结果为6(二进制为0b0110)
cout << (int)c; //输出6
将一个变量的值与一个表达式按位或,并将结果赋值给该变量:
unsigned int d = 0x1234; //十六进制数0x1234
d or_eq (1 << 8); //将d与256(即1<<8)按位或,结果为0x1334
cout << hex << d; //输出0x1334
override[C++11起]
含义
在C++11标准中,override关键字用于指示当前函数是重载基类中的虚函数。当一个函数被标记为“override”时,编译器会检查该函数是否与基类中的虚函数具有相同的名称、参数类型和返回类型。如果不是,则编译器将生成一个错误。
使用override的好处在于,它可以帮助程序员确保重载函数的正确性。如果程序员在派生类中意外地更改了虚函数的名称、参数类型或返回类型,编译器将会在编译时发出错误信息,以提醒程序员进行修复。
用法
以下是override关键字的示例:
// 基类
class Base {
public:
virtual void print() {
cout << "This is the Base class" << endl;
}
};
// 派生类
class Derived : public Base {
public:
virtual void print() override { // 使用override
cout << "This is the Derived class" << endl;
}
};
int main() {
Base* b = new Derived();
b->print(); // 输出 "This is the Derived class"
delete b;
return 0;
}
在上面的示例中,我们使用override关键字在派生类中重载了基类中的虚函数print()。在main函数中,我们创建了一个Derived类的实例,并将其赋值给一个Base类的指针。然后,我们调用指针的print()函数,它将调用Derived类中的print()函数,输出"This is the Derived class"。
// 基类
class Shape {
public:
virtual double area() const = 0;
};
// 派生类
class Rectangle : public Shape {
public:
double area() const override { // 使用override
return height * width;
}
private:
double height;
double width;
};
int main() {
Rectangle r;
r.area(); // 计算矩形的面积
return 0;
}
在上面的示例中,我们使用override关键字在Rectangle类中重载了Shape类中的虚函数area()。在main函数中,我们创建了一个Rectangle类的实例,并调用其area()函数来计算矩形的面积。
P字母
private
含义
private关键字用于指定类中的私有成员。私有成员是指只能在类的内部访问的成员变量和成员函数。私有成员不能被外部函数或类直接访问,只能通过类的公有成员函数来访问。
使用private关键字可以保证类的封装性,隐藏类的内部实现细节,防止外部程序员对类的私有成员变量和函数进行直接访问和操作,从而保证程序的安全性和稳定性。
用法
在类中定义私有成员变量:
class MyClass {
private:
int num;
public:
void setNum(int n) {
num = n;
}
int getNum() {
return num;
}
};
在上面的示例中,num为私有成员变量,只能在类的内部访问,外部程序员无法直接访问或修改它。setNum()和getNum()为公有成员函数,可以用于设置和获取num的值,外部程序员只能通过这些函数来访问num。
在类中定义私有成员函数:
class MyClass {
private:
void myPrivateFunc() {
cout << "This is a private function." << endl;
}
public:
void myPublicFunc() {
cout << "This is a public function." << endl;
myPrivateFunc(); // 在公有成员函数中调用私有成员函数
}
};
在上面的示例中,myPrivateFunc()为私有成员函数,只能在类的内部调用,外部程序员无法直接调用它。myPublicFunc()为公有成员函数,可以被外部程序员调用,它在内部调用了myPrivateFunc(),从而实现了对私有成员函数的间接访问。
在类中定义私有构造函数:
class MyClass {
private:
MyClass() {}
public:
static MyClass* getInstance() {
static MyClass* instance = new MyClass(); // 在公有静态函数中创建私有构造函数的实例
return instance;
}
};
在上面的示例中,MyClass的构造函数为私有成员函数,只能在类的内部调用,外部程序员无法直接调用它。getInstance()为公有静态函数,用于获取MyClass的实例,它在内部调用了MyClass的私有构造函数,从而实现了对构造函数的控制和封装。
protected
含义
C++中,protected关键字用于指定类成员的访问级别。protected成员可以被其派生类的成员访问,但不能被类的外部访问。
用法
protected关键字的作用主要有以下几点:
- 继承性:protected成员可以被派生类访问,从而实现了类成员在继承链中的传递性。
- 封装性:protected成员可以在类内部被访问,但不能被类的外部直接访问,从而保证了类的封装性。
- 隐藏实现细节:将实现细节隐藏在protected成员中,可以防止用户对类的实现进行非法访问或修改。
下面给出几个简单的例子:
class Base {
protected:
int m_protectedVar;
};
class Derived : public Base {
public:
void set(int value) {
m_protectedVar = value;
}
};
int main() {
Derived d;
d.set(10); // 正确,可以访问基类中的protected成员
return 0;
}
在上述例子中,派生类Derived可以访问基类Base中的protected成员m_protectedVar,从而实现了成员变量在继承链中的传递性。
class A {
protected:
int m_protectedVar;
};
class B : public A {
public:
void set(int value) {
m_protectedVar = value; // 正确,可以访问基类中的protected成员
}
};
class C {
private:
A m_a; // 错误,无法访问A类的protected成员
};
int main() {
B b;
b.set(10);
return 0;
}
在上述例子中,类C无法访问类A中的protected成员m_protectedVar,因为protected成员只能被类的派生类访问。而在类B中,由于继承了A类,可以访问A类中的protected成员。
class A {
protected:
int m_protectedVar;
};
class B {
public:
void set(A& a, int value) {
a.m_protectedVar = value; // 错误,无法访问A类的protected成员
}
};
int main() {
A a;
B b;
b.set(a, 10);
return 0;
}
在上述例子中,类B无法访问类A中的protected成员m_protectedVar,因为protected成员只能被类的派生类访问。而在main函数中,由于B类并没有继承A类,因此无法访问A类中的protected成员。
public
含义
C++中的public关键字是访问控制修饰符之一,它用于指定类成员的访问权限。public指定的成员可以在类的任何地方被访问,包括类的外部和内部。也就是说,public成员可以被任何对象访问。
public关键字的主要作用是实现类的封装。通过将类成员分为public、private和protected三种访问级别,可以控制类成员的访问权限,从而保护类的数据安全性和完整性。
用法
类的成员函数:
class Person {
public:
void speak() {
cout << "Hello, I'm a person." << endl;
}
};
在这个例子中,speak()函数是一个public成员函数,可以在类的内部和外部任何地方被访问。
类的成员变量:
class Person {
public:
string name;
};
在这个例子中,name变量是一个public成员变量,可以在类的内部和外部任何地方被访问。
类的继承:
class Student : public Person {
public:
void study() {
cout << "I'm studying." << endl;
}
};
在这个例子中,Student类继承自Person类,并使用public关键字指定继承类型为public。这意味着,在Student类中,Person类的public成员可以被直接访问。
字母R
register
含义
register关键字是C++中的一个存储类别,它用于向编译器建议将变量存储在寄存器中,以便提高程序的执行速度使用register关键字时,编译器会尝试将变量存储在CPU的寄存器中,从而避免了在内存中的访问,从而提高了程序的执行速度。但是,由于寄存器数量有限,编译器可能不会总是将变量存储在寄存器中,特别是当程序中使用register变量过多时。
用法
在函数中使用register关键字:
void foo() {
register int i; // 将i变量存储在寄存器中
// ...
}
在结构体中使用register关键字:
struct Point {
int x;
int y;
register int z; // 将z变量存储在寄存器中
};
在函数参数中使用register关键字:
void bar(register int i) {
// ...
}
需要注意的是,register关键字只是一种建议,编译器可以忽略它。此外,register关键字只能用于基本数据类型,而不能用于指针或数组等复杂数据类型。
reinterpret_cast
含义
C++中的reinterpret_cast关键字用于将一个指针或引用转换为另一种类型的指针或引用,即对指针或引用进行重新解释。它是C++中最危险的类型转换之一,因为它可以将一个指针或引用转换为任何其他类型的指针或引用,而不考虑原始类型和目标类型之间的任何关系。
用法
例如,我们可以使用reinterpret_cast将一个指向整数的指针转换为一个指向字符数组的指针,如下所示:
int num = 65;
char* chPtr = reinterpret_cast<char*>(&num);
std::cout << *chPtr << std::endl; // 输出'A'
在这个例子中,我们将一个指向整数的指针强制转换为一个指向字符数组的指针,并使用指针访问整数值的每个字节,以输出字符’A’。
另一个例子是将一个指向对象的指针转换为一个指向其基类的指针,如下所示:
class Base {
public:
virtual void foo() {}
};
class Derived : public Base {
public:
void foo() override {}
};
Derived d;
Base* bPtr = reinterpret_cast<Base*>(&d);
在这个例子中,我们将一个指向Derived对象的指针强制转换为一个指向其Base类的指针。由于Derived类是Base类的派生类,因此这种类型转换是安全的。
注意事项
需要注意的是,reinterpret_cast不能用于转换指针或引用之间的不同类型的对象。例如,将一个指向int的指针转换为一个指向double的指针是不安全的,因为它会导致数据的不正确解释和错误的结果。
总之,reinterpret_cast关键字是C++中最危险的类型转换之一,应谨慎使用。它可以用于一些特殊的情况,如将一个指向对象的指针转换为一个指向其基类的指针,但必须确保原始类型和目标类型之间的关系是安全的。
requires[C++20]
含义
requires是C++20引入的新关键字,用于指定模板参数对应的类型需要满足的要求。在C++中,模板可以接受任何类型的参数,但有时我们希望限制这些参数的类型必须满足某些条件。例如,我们可以要求模板参数必须是可调用对象、支持某种操作符或继承自某个特定的类等等。requires关键字正是为了满足这种需求而引入的。
用法
template <typename T>
requires <要求>
void func(T arg) {
// 函数体
}
其中,[要求]部分指定了模板参数T需要满足的要求,可以是一个表达式、函数调用、类型转换等。如果T不满足这些要求,编译器将会报错。
要求模板参数必须是可调用对象
template <typename T>
requires std::invocable<T>
void func(T arg) {
arg();
}
这个示例中,我们使用了std::invocable的概念来限制模板参数必须是可调用对象。如果我们传递给func的参数不是可调用对象,编译器将会报错。
要求模板参数必须支持某种操作符
template <typename T>
requires requires(T a, T b) {
a + b;
}
void func(T arg1, T arg2) {
// 函数体
}
这个示例中,我们使用了requires语法来指定模板参数必须支持加法操作符。如果我们传递给func的参数不支持加法操作符,编译器将会报错。
要求模板参数必须继承自某个特定的类
template <typename T>
requires std::is_base_of_v<Base, T>
void func(T arg) {
// 函数体
}
这个示例中,我们使用了std::is_base_of_v来限制模板参数必须继承自Base类。如果我们传递给func的参数不是Base类或其子类的实例,编译器将会报错。
注意事项
需要注意的是,requires关键字只能用于模板中,不能用于普通函数或变量。另外,requires语法还可以与其他的模板约束语法一起使用,例如requires和typename一起使用来指定模板参数必须是类型等。
return
含义
在C++中,return关键字用于从函数中返回值并退出函数。当函数遇到return语句时,它将立即停止执行并返回指定的值。如果函数没有指定返回值,则返回void。
用法
以下是几个示例:
返回整数类型的值:
int add(int a, int b) {
int sum = a + b;
return sum;
}
int result = add(2, 3); // 返回值为 5
返回布尔类型的值:
bool isEven(int num) {
if (num % 2 == 0) {
return true;
} else {
return false;
}
}
bool result = isEven(4); // 返回值为 true
返回字符类型的值:
char getGrade(int score) {
if (score >= 90) {
return 'A';
} else if (score >= 80) {
return 'B';
} else if (score >= 70) {
return 'C';
} else if (score >= 60) {
return 'D';
} else {
return 'F';
}
}
char result = getGrade(85); // 返回值为 'B'
返回void类型:
void printHello() {
std::cout << "Hello!" << std::endl;
return; // 可以省略
}
printHello(); // 输出 "Hello!"
S字母
short
含义
short关键字在C++中表示短整型,它可以用来声明一个变量,该变量的取值范围为-32768到32767。
使用short关键字可以节省内存空间,因为short类型的变量只需要2个字节的存储空间,而int类型的变量需要4个字节的存储空间。
用法
声明一个short类型的变量
short num = 100;
将一个整数赋值给short类型的变量
short num;
num = 32767;
将一个short类型的变量转换为int类型
short num = 100;
int result = num + 100;
在结构体中使用short类型的成员变量
struct student {
short age;
char name[20];
};
signed
含义
signed是C++中的关键字之一,它用于指示变量或类型是有符号的(可以表示正数、零或负数)。在C++中,整数类型默认为signed,因此signed通常可以省略。
用法
明确指定变量是有符号的
在C++中,整数类型默认为有符号类型。如果需要明确指定变量是有符号类型,可以使用signed关键字。例如:
signed int x = -10;
signed long y = -1000000000L;
与unsigned关键字搭配使用
在C++中,unsigned关键字用于指示变量或类型是无符号的(只能表示非负整数)。当需要同时使用有符号和无符号类型时,可以使用signed关键字与unsigned关键字分别指定变量的类型。例如:
signed int x = -10;
unsigned int y = 20;
避免类型溢出
在C++中,对于有符号类型的变量,若其值超出了其类型所能表示的范围,就会发生类型溢出。而对于无符号类型的变量,则会发生“回绕”(wrap around)。使用signed关键字可以避免类型溢出的情况。例如:
signed short x = 32767; // 正确
signed short y = 32768; // 错误,超出范围
signed关键字用于指示变量或类型是有符号的,可以明确指定变量的类型,与unsigned关键字搭配使用,以避免类型溢出等问题。
sizeof
含义
C++中的sizeof关键字可以用来计算数据类型或变量占用的字节数。sizeof关键字后面可以跟数据类型、变量名或表达式,返回对应的字节数。
用法
例如,对于一个整型变量,可以使用sizeof关键字来计算它占用的字节数:
int num = 10;
std::cout << "Size of int: " << sizeof(int) << std::endl; // 输出4,表示一个int类型占用4个字节
std::cout << "Size of num: " << sizeof(num) << std::endl; // 输出4,表示变量num占用4个字节
对于一个结构体,可以使用sizeof关键字来计算它占用的字节数:
struct Person {
char name[20];
int age;
bool isMale;
};
std::cout << "Size of Person: " << sizeof(Person) << std::endl; // 输出25,表示结构体Person占用25个字节
可以使用sizeof关键字来计算数组占用的字节数:
int arr[5] = {1, 2, 3, 4, 5};
std::cout << "Size of arr: " << sizeof(arr) << std::endl; // 输出20,表示数组arr占用20个字节
当使用sizeof关键字计算指针类型占用的字节数时,通常会得到4或8个字节,因为指针类型在32位或64位系统上占用4或8个字节。
int* p = #
std::cout << "Size of int*: " << sizeof(int*) << std::endl; // 输出4或8,表示指针类型int*占用4或8个字节
std::cout << "Size of p: " << sizeof(p) << std::endl; // 输出4或8,表示指针变量p占用4或8个字节
sizeof关键字可以方便地计算各种数据类型和变量占用的字节数,这对于内存分配和优化程序性能非常有用。
static
用法
C++中的static关键字有以下几种功能
修饰全局变量或函数:使其作用域限制在文件内,不能被其他文件调用或访问。
static int count = 0; // 修饰全局变量,只能在当前文件内访问
static void func() { // 修饰全局函数,只能在当前文件内调用
cout << "Hello World" << endl;
}
修饰类的成员变量或函数:使其成为类的静态成员,即不属于任何一个对象,而是属于整个类。
例如:
class MyClass {
public:
static int count; // 声明静态成员变量
static void func() { // 声明静态成员函数
cout << "Hello World" << endl;
}
};
int MyClass::count = 0; // 静态成员变量需要在类外进行定义和初始化
int main() {
MyClass::count++; // 可以通过类名直接访问静态成员变量
MyClass::func(); // 可以通过类名直接调用静态成员函数
return 0;
}
修饰局部变量:使其在程序运行期间只初始化一次,并且不能被其他函数访问。
void func() {
static int count = 0; // 只会初始化一次
cout << "Count: " << count++ << endl;
}
int main() {
func(); // 输出Count: 0
func(); // 输出Count: 1
func(); // 输出Count: 2
return 0;
}
C++中的static关键字可以修饰全局变量或函数、类的成员变量或函数以及局部变量,具体作用取决于修饰的对象。一般来说,static关键字用于实现信息的隐藏和共享,或者在程序运行期间只初始化一次。
static_cast
含义
C++中的static_assert关键字是用于在编译时检查某些条件是否成立的一种机制。它可以在编译时断言某个表达式的值为真,如果表达式的值为假,则会导致编译错误。
用法
static_cast可以用于以下情况:
-
- 类型转换:将一种类型转换为另一种类型,如将int类型转换为double类型。
-
- 向上转型:将一个子类指针或引用转换为父类指针或引用。
-
- 向下转型:将一个父类指针或引用转换为子类指针或引用。
-
- 隐式类型转换:将一个表达式的类型转换为另一个表达式的类型,如将一个char类型转换为int类型。
- 隐式类型转换:将一个表达式的类型转换为另一个表达式的类型,如将一个char类型转换为int类型。
类型转换
int i = 10;
double d = static_cast<double>(i); //将int类型转换为double类型
向上转型
class Base {
public:
virtual void print() {
cout << "This is Base class." << endl;
}
};
class Derived : public Base {
public:
void print() {
cout << "This is Derived class." << endl;
}
};
Derived d;
Base& b = static_cast<Base&>(d); //将Derived类的对象转换为Base类的引用
向下转型
Base* b = new Derived();
Derived* d = static_cast<Derived*>(b); //将Base类指针转换为Derived类指针
隐式类型转换
int i = 97;
char c = static_cast<char>(i); //将int类型转换为char类型,输出字符'a'
static_assert[C++11起]
含义
C++中的static_assert关键字是用于在编译时检查某些条件是否成立的一种机制。它可以在编译时断言某个表达式的值为真,如果表达式的值为假,则会导致编译错误。
用法
static_assert的语法格式如下:
static_assert(expression, message);
其中,expression是要检查的表达式,message是在expression为假时输出的错误信息。 message可以是一个字符串常量,也可以是一个表达式。
下面是几个static_assert的例子:
检查某个值是否为正数:
template<typename T>
void printPositive(T value)
{
static_assert(std::is_integral<T>::value, "T must be an integral type");
static_assert(std::is_signed<T>::value, "T must be a signed type");
static_assert(value > 0, "value must be positive");
std::cout << value << std::endl;
}
上面的代码用于打印一个正整数,它会在编译时检查传入的值是否为正数,如果不是则会输出错误信息。
检查结构体的大小是否符合要求:
struct Person
{
int age;
char name[20];
};
static_assert(sizeof(Person) <= 32, "Person struct is too large");
上面的代码用于检查Person结构体的大小是否小于等于32字节,如果超过了则会输出错误信息。
检查某个模板参数是否为某个类型:
template<typename T>
class MyClass
{
static_assert(std::is_same<T, int>::value, "T must be int");
};
上面的代码用于检查模板参数T是否为int类型,如果不是则会输出错误信息。
struct
含义
struct是C++中用于定义自定义数据类型的关键字。它可以将不同类型的数据组合在一起,形成一个新的数据类型,方便程序中的数据管理和使用。
用法
struct Student {
int id;
string name;
int age;
};
上面的代码定义了一个名为Student的结构体,其中包含了学生的id、姓名和年龄三个属性。我们可以将这个结构体看作是一个包含了这三个属性的整体,方便对学生信息进行管理和操作。
定义好结构体之后,我们可以创建结构体类型的变量,并对其属性进行赋值和访问:
Student s;
s.id = 1001;
s.name = "张三";
s.age = 18;
cout << s.name << "的年龄是" << s.age << endl;
上面的代码创建了一个名为s的Student类型的变量,并对其属性进行了赋值。我们可以通过点运算符来访问结构体变量中的属性,比如上面的cout语句就输出了s变量的姓名和年龄。
除了定义简单的数据类型,struct还可以嵌套使用,形成更加复杂的数据类型。比如我们可以定义一个表示学生课程成绩的数据类型:
struct Score {
string course;
double grade;
};
struct Student {
int id;
string name;
int age;
Score scores[3];
};
上面的代码中,我们在Student结构体中嵌套了一个Score结构体数组,用来表示学生的三门课程成绩。这样一来,我们就可以通过一个Student类型的变量来同时管理学生的个人信息和课程成绩信息。
switch
含义
C++中的switch关键字用于多分支条件控制语句,它可以根据不同的情况执行不同的代码块
用法
switch(expression) {
case constant-expression:
statement(s);
break;
case constant-expression:
statement(s);
break;
default:
statement(s);
}
其中,expression是要进行条件判断的变量或表达式,case是要匹配的常量表达式,如果expression的值与某个case的值相等,则执行该case下的语句块。如果expression的值与所有case的值都不相等,则执行default下的语句块。break语句用于终止某个case下的语句块,如果没有break语句,则会继续执行下一个case的语句块。
判断一个数字是奇数还是偶数
int num = 5;
switch(num % 2) {
case 0:
cout << num << " is even";
break;
case 1:
cout << num << " is odd";
break;
}
判断一个字符是元音字母还是辅音字母
char ch = 'a';
switch(ch) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
cout << ch << " is a vowel letter";
break;
default:
cout << ch << " is a consonant letter";
break;
}
根据用户的输入进行相应的操作
int choice;
cout << "1. Add" << endl;
cout << "2. Subtract" << endl;
cout << "3. Multiply" << endl;
cout << "4. Divide" << endl;
cout << "Enter your choice: ";
cin >> choice;
switch(choice) {
case 1:
cout << "Addition selected";
//调用加法函数
break;
case 2:
cout << "Subtraction selected";
//调用减法函数
break;
case 3:
cout << "Multiplication selected";
//调用乘法函数
break;
case 4:
cout << "Division selected";
//调用除法函数
break;
default:
cout << "Invalid choice";
break;
}
T字母
template
C++模板是一种可重用代码的机制,它允许程序员编写通用的函数或类,可以应对不同的数据类型。模板使用类型参数,使得同一个代码可以用于不同的数据类型,从而提高了代码的可重用性。
C++中有两种类型的模板:函数模板和类模板。函数模板允许程序员编写一个通用的函数,该函数可以接受不同的参数类型。类模板允许程序员编写一个通用的类,该类可以用于不同的数据类型。
用法
函数模板
假设我们设计一个交换两个整型变量的值的函数,代码如下:
// 交换两个整型变量的值的Swap函数:
void Swap(int & x,int & y)
{
int tmp = x;
x = y;
y = tmp;
}
如果是浮点类型的变量的值交换,则替换 int 类型为 double 即可,代码如下:
// 交换两个double型变量的值的Swap函数:
void Swap(double & x,double & y)
{
double tmp = x;
x = y;
y = tmp;
}
那如果是其他变量类型的值交换,那不是每次都要重新写一次 Swap 函数?是不是很繁琐?且代码后面会越来越冗余。能否只写一个 Swap 函数,就能交换各种类型的变量?答案是肯定有的,就是用「函数模板」来解决,「函数模板」的形式:
template <class T>
void Swap(T & x,T & y)
{
T tmp = x;
x = y;
y = tmp;
}
int main()
{
int n = 1,m = 2;
Swap(n,m); //编译器自动生成 void Swap(int & ,int & )函数
double f = 1.2,g = 2.3;
Swap(f,g); //编译器自动生成 void Swap(double & ,double & )函数
return 0;
}
求数组中的最大值的函数模板
// 求数组最大元素的MaxElement函数模板
template <class T>
T MaxElement(T a[], int size) // size是数组元素个数
{
T tmpMax = a[0];
for(int i = 1;i < size;++i)
{
if(tmpMax < a[i])
{
tmpMax = a[i];
}
}
return tmpMax;
}
类模板
为了多快好省地定义出一批相似的类,可以定义「类模板」,然后由类模板生成不同的类。
template <class T> //声明一个模板,虚拟类型名为T。注意:这里没有分号。
class Compare //类模板名为Compare
{
public :
Compare(T a,T b)
{
x=a;y=b;
}
T max( )
{
return (x>y)?x:y;
}
T min( )
{
return (x<y)?x:y;
}
private :
T x,y;
};
int main ()
{
Compare <int> cmp(4, 7);
Compare <float> cmp(4.0, 7.0);
return 0;
}
函数模板作为类模板的成员
#include<iostream>
using namespace std;
template <class T>
class A
{
public:
template<class T2>
void Func(T2 t) { cout << t; } // 成员函数模板
};
int main()
{
A<int> a;
a.Func('K'); //成员函数模板 Func被实例化
a.Func("hello"); //成员函数模板 Func再次被实例化
return 0;
}
// 输出结果为Khello
类模板的“ [类型参数表]”中可以出现非类型参数:
template <class T, int size>
class CArray
{
public:
void Print( )
{
for( int i = 0;i < size; ++i)
cout << array[i] << endl;
}
private:
T array[size];
};
CArray<double,40> a2;
CArray<int,50> a3; //a2和a3属于不同的类
类模板与派生
template <class T1,class T2>
class A
{
T1 v1; T2 v2;
};
template <class T>
class B:public A<int,double> // A<int,double> 模板类
{
T v;
};
int main()
{
//自动生成两个模板类 :A<int,double> 和 B<char>
B<char> obj1;
return 0;
}
普通类从模板派生
template <class T>
class A
{
T v1;
};
class B:public A<int>
{
double v;
};
int main()
{
B obj1;
return 0;
}
函数、类、类的成员函数作为类模板的友元
// 普通函数
void Func1() { }
// 普通类
class A { };
// 普通类
class B
{
public:
void Func() { } // 成员函数
};
// 类模板
template <class T>
class Tmp
{
friend void Func1(); // 友元函数
friend class A; // 友元类
friend void B::Func(); // 友元类的成员函数
}; // 任何从 Tmp 实例化来的类 ,都有以上三个友元
函数模板作为类模板的友元
// 类模板
template <class T1,class T2>
class Pair
{
private:
T1 key; //关键字
T2 value; //值
public:
Pair(T1 k,T2 v):key(k),value(v) { };
// 友元函数模板
template <class T3,class T4>
friend ostream & operator<< (ostream & o, const Pair<T3,T4> & p);
};
// 函数模板
template <class T3,class T4>
ostream & operator<< (ostream & o, const Pair<T3,T4> & p)
{
o << "(" << p.key << "," << p.value << ")" ;
return o;
}
int main()
{
Pair<string,int> student("Tom",29);
Pair<int,double> obj(12,3.14);
cout << student << " " << obj;
return 0;
}
//输出:(Tom,29) (12,3.14)
函数模板作为类的友元
// 普通类
class A
{
private:
int v;
public:
A(int n):v(n) { }
template <class T>
friend void Print(const T & p); // 函数模板
};
// 函数模板
template <class T>
void Print(const T & p)
{
cout << p.v;
}
int main()
{
A a(4);
Print(a);
return 0;
}
//输出:4
类模板作为类模板的友元
// 类模板
template <class T>
class B
{
private:
T v;
public:
B(T n):v(n) { }
template <class T2>
friend class A; // 友元类模板
};
// 类模板
template <class T>
class A
{
public:
void Func( )
{
B<int> o(10); // 实例化B模板类
cout << o.v << endl;
}
};
int main()
{
A<double> a;
a.Func ();
return 0;
}
//输出为10
类模板与静态成员变量
template <class T>
class A
{
private:
static int count; // 静态成员
public:
A() { count ++; }
~A() { count -- ; };
A( A & ) { count ++ ; }
static void PrintCount() { cout << count << endl; } // 静态函数
};
template<> int A<int>::count = 0; // 初始化
template<> int A<double>::count = 0; // 初始化
int main()
{
A<int> ia;
A<double> da; // da和ia不是相同模板类
ia.PrintCount();
da.PrintCount();
return 0;
}
//输出 : 1
// 1
注意事项
在类模板外定义函数,不能用一般定义类成员函数的形式
T Compare::max( ) {…} //不能这样定义类模板中的成员函数
// 应该这样写
template <class T>
T Compare<T>::max( )
{
return (x > y)? x : y;
}
同一个类模板的两个模板类是不兼容的
Pair<string,int> *p;
Pair<string,double> a;
p = & a; //错误!!
this
含义
在C++中,this关键字是一个指向当前对象的指针。它可以在类的成员函数中使用,用于访问当前对象的成员变量和成员函数。this指针是一个隐藏的参数,它不需要像普通参数一样显示传递,编译器会自动处理。
用法
this指针的作用主要有以下几个:
解决变量名冲突问题:当类的成员变量和函数参数同名时,使用this指针可以区分它们。例如:
class Demo {
public:
void setNum(int num) {
this->num = num;
}
private:
int num;
};
在类的成员函数中返回当前对象的引用,以支持链式调用。例如:
class Demo {
public:
Demo& add(int num) {
this->num += num;
return *this;
}
private:
int num;
};
在构造函数和析构函数中访问当前对象。例如:
class Demo {
public:
Demo(int num) {
this->num = num;
}
~Demo() {
// do something with this->num
}
private:
int num;
};
this指针是C++中一个非常重要的关键字,它可以帮助我们访问当前对象的成员变量和成员函数,解决变量名冲突问题,支持链式调用,以及在构造函数和析构函数中访问当前对象。
throw
含义
throw是C++中的一个关键字,用于抛出异常。当程序发生错误或异常情况时,可以使用throw语句抛出异常对象,由上层调用者或系统处理异常。
用法
throw语句的语法如下:
throw expression;
其中expression是一个异常对象,可以是任何类型的表达式,包括一个变量、一个常量、一个函数调用等。
当throw语句被执行时,程序会跳出当前的try块,并且异常对象会被传递给最近的catch块进行处理。如果没有找到匹配的catch块,则程序会终止并且输出错误信息。
以下是一个简单的示例,演示了如何使用throw抛出异常:
#include <iostream>
using namespace std;
int divide(int a, int b) {
if (b == 0) {
throw "Divide by zero";
}
return a / b;
}
int main() {
int a = 10, b = 0;
try {
int c = divide(a, b);
cout << "Result: " << c << endl;
} catch(const char* error) {
cout << "Error: " << error << endl;
}
return 0;
}
在这个示例中,divide函数用于计算a/b,如果b为0,则抛出一个const char*类型的异常对象。在main函数中,使用try-catch语句捕获异常并输出错误信息。
注意事项
throw语句可以抛出任何类型的异常对象,包括自定义的异常类对象。在实际开发中,可以通过自定义异常类来表示特定的错误或异常情况,并且使用throw语句抛出该异常类对象。
thread_local
含义
C++11引入了关键字thread_local,用于声明线程局部存储(TLS)变量。线程局部存储变量是指在不同线程之间具有不同值的变量。
使用thread_local声明的变量只能在声明它的线程中访问,其他线程无法访问。该关键字可以用于全局变量、静态变量和局部静态变量。
用法
线程安全的单例模式
使用thread_local关键字可以实现线程安全的单例模式。在多线程环境下,单例模式需要保证只有一个实例被创建。使用thread_local关键字可以保证每个线程都只有一个实例。
class Singleton {
private:
static thread_local Singleton* instance;
Singleton() {}
public:
static Singleton* getInstance() {
if (!instance) {
instance = new Singleton();
}
return instance;
}
};
thread_local Singleton* Singleton::instance = nullptr;
线程局部计数器
在多线程环境下,需要保证计数器的线程安全。使用thread_local关键字可以为每个线程创建一个独立的计数器。
void increment() {
static thread_local int counter = 0;
++counter;
cout << "Counter value: " << counter << endl;
}
int main() {
thread t1(increment);
thread t2(increment);
t1.join();
t2.join();
return 0;
}
输出结果:
Counter value: 1
Counter value: 1
每个线程都有自己的计数器,可以独立地增加计数器的值。
线程局部变量实现线程池
使用线程池可以提高程序的性能,但是需要保证每个线程都有自己的变量。使用thread_local关键字可以为每个线程创建一个独立的变量。
void worker() {
static thread_local int id = 0;
while (true) {
Task task = taskQueue.pop();
task(id);
}
}
int main() {
ThreadPool pool(4);
for (int i = 0; i < 10; ++i) {
pool.submit([](int id) {
cout << "Thread " << id << " is running" << endl;
});
}
pool.shutdown();
return 0;
}
true
含义
true关键字是一个布尔值,表示真的状态。它的值为1。true通常在条件语句和循环中使用,用于判断条件是否成立。
用法
下面是一些使用true关键字的例子:
条件语句中使用true
int x = 5;
if (x > 0) {
cout << "x is greater than 0" << endl;
}
在这个例子中,如果x的值大于0,条件成立,输出"x is greater than 0"。因为x的值是5,所以条件成立。
循环语句中使用true
int x = 0;
while (true) {
x++;
if (x > 10) {
break;
}
}
cout << "x is " << x << endl;
在这个例子中,我们使用while循环来让x的值加1,直到x的值大于10。我们使用true作为循环条件,这意味着循环会一直执行,直到我们使用break关键字来跳出循环。
函数返回true
bool isPositive(int x) {
if (x > 0) {
return true;
} else {
return false;
}
}
int main() {
int x = 5;
if (isPositive(x)) {
cout << "x is positive" << endl;
} else {
cout << "x is not positive" << endl;
}
return 0;
}
在这个例子中,我们定义了一个函数isPositive,它接受一个整数参数x,并返回一个布尔值,表示x是否为正数。如果x大于0,函数返回true,否则返回false。在主函数中,我们调用isPositive函数来判断x是否为正数,并输出相应的结果。因为x的值是5,所以isPositive函数返回true,输出"x is positive"。
typedef
含义
typedef关键字在C++中的作用是给一个已有的数据类型起一个新的别名。这个别名可以用来定义新的变量,函数参数,结构体和类等。
用法
例如,我们可以使用typedef来定义一个新的类型名称,如下所示:
typedef int myInt;
这将创建一个名为myInt的新类型,它是int类型的别名。现在我们可以使用myInt来定义变量,就像我们使用int一样:
myInt x = 10;
我们也可以使用typedef来定义指向某个类型的指针:
typedef int* intPtr;
这将创建一个名为intPtr的新类型,它是int*类型的别名。现在我们可以使用intPtr来定义指向整数的指针,就像这样:
intPtr p = new int;
*p = 5;
我们也可以使用typedef来定义结构体的新名称,例如:
typedef struct {
int x;
int y;
} Point;
这将创建一个名为Point的新类型,它是一个包含x和y成员的结构体的别名。现在我们可以使用Point来定义结构体变量:
Point p1 = {0, 0};
Point p2 = {1, 2};
typeid
含义
C++中的typeid关键字用于获取一个类型的信息,包括类型的名称和类型的实例。它的作用类似于Java中的getClass()方法,可以用来判断两个对象是否为同一类型,或者获取对象的类型信息。
用法
typeid关键字可以用于以下两种情况:
获取类型的名称:
通过typeid关键字可以获取一个类型的名称,例如:
#include <iostream>
#include <typeinfo>
using namespace std;
int main() {
int i = 10;
cout << typeid(i).name() << endl;
return 0;
}
输出结果为:i。此处的typeid(i)返回一个std::type_info类型的对象,调用其.name()方法可以获取该类型的名称。
判断类型是否相同:
通过typeid关键字可以判断两个类型是否相同,例如:
#include <iostream>
#include <typeinfo>
using namespace std;
int main() {
int i = 10;
double d = 3.14;
cout << (typeid(i) == typeid(d)) << endl;
return 0;
}
输出结果为:0。即i和d不是同一类型。
下面再举两个例子:
#include <iostream>
#include <typeinfo>
using namespace std;
class A{};
class B : public A{};
int main() {
A* pA = new B;
cout << typeid(*pA).name() << endl;
return 0;
}
输出结果为:B。即pA指向的对象是B类型的。
#include <iostream>
#include <typeinfo>
using namespace std;
template<typename T>
void getType(T t) {
cout << typeid(T).name() << endl;
}
int main() {
int i = 10;
getType(i);
return 0;
}
输出结果为:int。即模板参数T的类型为int。
typename
含义
typename关键字主要用于指定一个类型名。它通常与模板一起使用,用于指定模板中的类型参数。在模板中,当使用一个未知类型时,C++编译器无法确定这个未知类型是否是一个类型名,而typename关键字就是用来告诉编译器,这个未知的名字是一个类型名。
用法
以下是一个简单的例子:
template <typename T>
void myFunction() {
typename T::iterator iter; // T::iterator表示一个类型,需要使用typename关键字告诉编译器
// do something with iter
}
在上面的例子中,T::iterator表示一个类型,但编译器无法确定它是否是一个类型名。因此,需要使用typename关键字告诉编译器这是一个类型名。
另一个例子:
template <typename T>
class MyClass {
public:
typename T::iterator begin(); // T::iterator表示一个类型,需要使用typename关键字告诉编译器
// other member functions
};
在上面的例子中,begin()返回T::iterator类型的迭代器,但编译器无法确定T::iterator是否是一个类型名。因此,需要使用typename关键字告诉编译器这是一个类型名。
U字母
union
含义
C++中的union关键字用于定义一种特殊的数据结构,它允许在同一块内存空间中存储不同的数据类型,但同一时间只能存储其中的一种数据类型。
union的作用是可以节省内存空间,在需要存储多种类型的数据时,可以使用union来定义一个共用体,这个共用体中的每个成员变量可以存储不同类型的数据,但是只能使用其中一种数据类型,这样可以节省内存空间。
用法
下面是一个简单的例子:
union Data {
int i;
float f;
char str[20];
};
在这个例子中,我们定义了一个名为Data的共用体,它包含了三个成员变量i、f和str,分别代表了整数、浮点数和字符数组,它们共用同一块内存空间。
下面是一个使用共用体的例子:
Data data;
data.i = 10;
cout << data.i << endl;
data.f = 3.14;
cout << data.f << endl;
strcpy(data.str, "hello");
cout << data.str << endl;
在这个例子中,我们首先给data的i成员变量赋值为10,然后输出i的值。接着,我们又给data的f成员变量赋值为3.14,然后输出f的值。最后,我们使用strcpy函数给data的str成员变量赋值为"hello",然后输出str的值。
由于共用体中的成员变量共用同一块内存空间,因此在给一个成员变量赋值后,如果再给另一个成员变量赋值,前一个成员变量的值会被覆盖掉。
下面再举一个例子:
union Example {
int i;
double d;
};
在这个例子中,我们定义了一个名为Example的共用体,它包含了两个成员变量i和d,分别代表了整数和双精度浮点数,它们共用同一块内存空间。
使用共用体时需要注意以下几点:
注意事项
-
共用体中的成员变量共用同一块内存空间,因此在给一个成员变量赋值后,如果再给另一个成员变量赋值,前一个成员变量的值会被覆盖掉。
-
共用体的大小等于其最大成员变量的大小。
-
在使用共用体时,需要明确指定要使用的成员变量。
unsigned
含义
unsigned是C++中的一个关键字,用于定义无符号类型的变量或函数参数。无符号类型的变量只能存储非负整数,即0或正整数,不包括负数。
使用unsigned关键字可以提高变量的表示范围,因为无符号变量不需要存储符号位,可以用来表示更大的数值范围,例如无符号整数的范围为04294967295,而有符号整数的范围为-21474836482147483647。
用法
以下是一些使用unsigned关键字的示例:
定义无符号整型变量:
unsigned int num1 = 10;
unsigned long num2 = 1234567890;
使用无符号整型变量作为函数参数:
void printNum(unsigned int num) {
cout << num << endl;
}
遍历数组时使用无符号整型变量:
int arr[] = {1, 2, 3, 4, 5};
unsigned int index;
for (index = 0; index < sizeof(arr) / sizeof(arr[0]); index++) {
cout << arr[index] << endl;
}
using
含义
using关键字在C++语言中有多种用途,主要包括以下几个方面:
用法
别名定义
using关键字可以用来定义类型别名,使得程序员可以使用一个简短、易懂的名称来表示一个较为复杂的类型。例如:
using int_ptr = int*; // 将 int* 类型定义为 int_ptr
int_ptr p = new int(10); // 使用 int_ptr 来定义指针变量
这里使用using关键字将int*类型定义为int_ptr,然后使用int_ptr来定义一个指向整型变量的指针。
命名空间引入
using关键字可以用来引入命名空间中的名称,使得程序员可以直接使用该名称而无需使用限定符。例如:
using std::cout; // 将 std::cout 引入到当前命名空间中
cout << "Hello, world!" << endl; // 直接使用 cout 输出字符串
这里使用using关键字将std::cout引入到当前命名空间中,然后直接使用cout来输出字符串。
模板别名定义
using关键字可以用来定义模板别名,使得程序员可以使用一个简短、易懂的名称来表示一个较为复杂的模板类型。例如:
template <typename T>
using vector_ptr = std::unique_ptr<std::vector<T>>; // 将 std::unique_ptr<std::vector<T>> 类型定义为 vector_ptr<T>
vector_ptr<int> p(new std::vector<int>()); // 使用 vector_ptr<int> 来定义智能指针变量
这里使用using关键字将std::unique_ptr<std::vector>类型定义为vector_ptr,然后使用vector_ptr来定义一个指向int向量的智能指针。
字母V
virtual
含义
C++中的virtual关键字用于声明虚函数。虚函数是一个可以在子类中被重写的函数,在运行时动态绑定到正确的实现。这意味着即使使用基类指针或引用调用虚函数,也可以调用子类中的实现。
用法
例如,假设有一个基类Animal和一个子类Dog:
class Animal {
public:
virtual void make_sound() {
cout << "The animal makes a sound." << endl;
}
};
class Dog : public Animal {
public:
void make_sound() {
cout << "The dog barks." << endl;
}
};
在这个例子中,make_sound()被声明为虚函数。在Dog中,它被重写以输出狗吠声。如果使用Animal指针或引用调用make_sound(),将调用Dog中的实现。
Animal* animal = new Dog();
animal->make_sound(); // 输出 "The dog barks."
虚函数的另一个用途是实现多态性。多态性是指允许使用基类类型的指针或引用来引用派生类对象,并在运行时确定使用的实际类型。这可以通过在基类中声明虚函数来实现。
例如,假设有一个基类Shape和两个子类Rectangle和Circle:
class Shape {
public:
virtual double area() {
return 0;
}
};
class Rectangle : public Shape {
public:
double area() {
return width * height;
}
private:
double width;
double height;
};
class Circle : public Shape {
public:
double area() {
return 3.14 * radius * radius;
}
private:
double radius;
};
在这个例子中,Shape中的area()被声明为虚函数。在Rectangle和Circle中,它们被重写以计算矩形和圆的面积。现在可以使用Shape指针或引用来引用Rectangle或Circle,并调用它们的area()函数,从而实现多态性。
Shape* shape = new Rectangle();
cout << shape->area() << endl; // 输出矩形的面积
shape = new Circle();
cout << shape->area() << endl; // 输出圆的面积
volatile
含义
在C++中,volatile关键字用于指示编译器在编译代码时不要对被声明为volatile的变量进行优化,以保证对变量的访问是按照程序中规定的顺序进行的,而不是被编译器优化后的顺序。在wchar_t类型中,volatile关键字的作用和其他数据类型中的一样,主要有以下两个方面:
用法
防止编译器优化
wchar_t类型的变量在某些情况下可能会被编译器优化,例如在多线程的情况下,变量可能被多个线程同时访问,而编译器可能会将变量缓存到寄存器中,导致多个线程访问的不是同一个内存地址。这时,使用volatile关键字可以告诉编译器不要对变量进行优化,以确保多线程的正确性。
volatile wchar_t flag = 0;
// 线程1
while (flag == 0) {
// do something
}
// 线程2
flag = 1;
在上面的代码中,flag变量被声明为volatile,这样编译器就不会对它进行优化,从而保证线程1中的循环能够正确地检测到flag变量的变化。
提高程序的可读性和可维护性
在一些特殊的场景下,使用volatile关键字可以使程序更加易于理解和维护。例如,当程序需要访问硬件寄存器或者其他外部资源时,使用volatile关键字可以保证对这些资源的访问是按照程序中规定的顺序进行的。
volatile wchar_t *p_reg = (volatile wchar_t *)0x1234; // 假设0x1234是某个硬件寄存器的地址
// 读取寄存器的值
wchar_t val = *p_reg;
// 写入寄存器的值
*p_reg = 0x5678;
在上面的代码中,p_reg指向一个硬件寄存器的地址,并且被声明为volatile,这样就可以确保读取和写入寄存器的操作是按照程序中规定的顺序进行的,从而保证程序的正确性。
字母W
wchar_t
含义
wchar_t:用于定义宽字符类型,通常用于支持Unicode编码的字符串操作。wchar_t占用2或4个字节,取决于编译器的实现
用法
wchar_t ch = L'中'; // 定义一个宽字符变量,存储中文字符
L:用于将字符常量转换为宽字符常量。L是一个前缀,表示后面的字符常量应该被解释为宽字符。
例如:
wchar_t ch = L'中'; // 定义一个宽字符变量,存储中文字符
wcin:用于从控制台读取宽字符输入。wcin是一个标准输入流,可以使用>>运算符从控制台读取宽字符。
例如:
wchar_t ch;
wcin >> ch; // 从控制台读取一个宽字符
wcout:用于将宽字符输出到控制台。wcout是一个标准输出流,可以使用"<<"运算符将宽字符输出到控制台。
例如:
wchar_t ch = L'中';
wcout << ch << endl; // 将宽字符输出到控制台
wcslen:用于计算宽字符串的长度。wcslen函数返回宽字符串中字符的数量,不包括结尾的0。
例如:
const wchar_t* str = L"Hello, world!";
size_t len = wcslen(str); // 计算宽字符串的长度
wmemcmp:用于比较两个宽字符数组。wmemcmp函数比较两个宽字符数组的内容,如果相同返回0,否则返回非0值。
const wchar_t* str1 = L"Hello, world!";
const wchar_t* str2 = L"Hello, world!";
int result = wmemcmp(str1, str2, wcslen(str1)); // 比较两个宽字符数组
if (result == 0) {
wcout << L"The two strings are equal." << endl;
} else {
wcout << L"The two strings are not equal." << endl;
}
while
含义
while是C++中的一个循环语句,其作用是在指定条件为真的情况下重复执行一段代码块,直到条件为假为止。
用法
while语句的语法格式如下:
while (condition) {
// 循环体
}
其中,condition是一个可计算的表达式,当其结果为真时,循环体会被执行,否则跳出循环。循环体是一段代码块,可以包含任意数量的语句,常用于处理重复性任务。
以下是一些while的示例:
使用while循环计算1到100的和:
int sum = 0;
int i = 1;
while (i <= 100) {
sum += i;
i++;
}
使用while循环读取用户输入的数字,直到输入0为止:
int num;
cout << "请输入数字,输入0结束:" << endl;
cin >> num;
while (num != 0) {
// 处理输入的数字
cin >> num;
}
使用while循环遍历数组中的元素,查找特定值的位置:
int arr[] = {1, 2, 3, 4, 5};
int target = 3;
int i = 0;
while (i < 5 && arr[i] != target) {
i++;
}
if (i < 5) {
cout << "找到了,位置是:" << i << endl;
} else {
cout << "没找到!" << endl;
}
在以上示例中,while循环的条件分别是i小于等于100、num不等于0、i小于5且arr[i]不等于target。这些条件满足时,循环体会被重复执行。
X字母
xor
含义
C++中的xor是一种位运算符,用于进行二进制位的异或操作。它的关键字是^,可以用于整型、字符型、布尔型等数据类型之间的操作,其作用是将两个数的二进制位进行比较,相同则为0,不同则为1。
用法
整数的异或操作
int a = 5; // 二进制为0101
int b = 3; // 二进制为0011
int c = a ^ b; // 二进制为0110,即6
字符的异或操作
char a = 'a'; // ASCII码为97,二进制为01100001
char b = 'b'; // ASCII码为98,二进制为01100010
char c = a ^ b; // 二进制为00000011,即3
布尔型的异或操作
bool a = true;
bool b = false;
bool c = a ^ b; // true
注意事项
异或操作具有可逆性,即a ^ b ^ b = a。因此,可以利用异或操作进行加密解密等操作。
xor_eq
含义
C++中的xor_eq是一个位运算符,并且是一个复合赋值运算符,表示按位异或并赋值,其作用是将两个操作数进行按位异或运算,并将结果赋值给左侧的操作数。具体来说,如果两个操作数的某一位都为1或都为0,则该位的结果为0,否则为1。
用法
int a = 5; // 二进制为 0101
a ^= 3; // 二进制为 0011,按位异或后变为 0110,即6
上述代码中,a ^= 3的结果是将a与3按位异或,并将结果赋值给a,即a的值变为6。
unsigned int x = 0xAAAAAAAA;
unsigned int y = 0x55555555;
x ^= y; // 二进制为 11111111 11111111 11111111 11111111
上述代码中,x和y的二进制分别为1010…和0101…交替出现,按位异或后得到全1的二进制数。