第1章:杂叙
1.名字空间 namespace xxx 在main函数中划分变量 空间时,需要 指定“xxx::a=1”
2.倘若需要使用cin 和 cout,需要在main函数外使用 using std::cin;或者从 using std::cout;标准库中的名字都属于标准名字空间std
3.变量存在的意义时为了方便管理内存空间
4 .程序块内定义内部变量,作用域在程序块内,隐藏外部变量。
6.引用变量 double &b=a;//b是a的别名,b就是a,引用变量经常用作函数的 形式参数,表示形参和实参是同一个对象,修改实参就修改形参。
7.swap函数交换x,y,内部需要借助临时变量temp去接收x,y中的x。 当交换数据内存较大时,最好不要复制数值,可以使用指针去交换地址。
8.define 定义宏常量,const修饰的变量,都是不可修改(写入函数体内部),否则报错。
9.
-
重写 是在派生类中改变基类方法的行为。
-
重载 是在同一个类中为同一个操作提供多种方法实现。
10.单冒号 ":" 是指子类继承基类
双冒号 “::”指出函数是属于哪个类的 " BOOL MyAPP::InitInstance()
",指出 InitInstance
函数是 MyAPP
类的成员,用于域解析。
11.std命名空间:
-
基础类型:
-
std::size_t
-
std::ptrdiff_t
-
-
字符串操作:
-
std::string
-
std::wstring
-
std::string_view
(C++17)
-
-
输入输出:
-
std::cout
-
std::cin
-
std::cerr
-
std::endl
-
std::flush
-
-
数学库:
-
std::abs
-
std::sqrt
-
std::pow
-
std::sin
,std::cos
,std::tan
等
-
-
数据结构:
-
std::vector
-
std::list
-
std::deque
-
std::array
-
std::map
-
std::unordered_map
-
std::set
-
std::unordered_set
-
std::stack
-
std::queue
-
std::priority_queue
-
-
算法:
-
std::sort
-
std::find
-
std::count
-
std::copy
-
std::transform
-
std::accumulate
-
-
内存管理:
-
std::malloc
-
std::calloc
-
std::realloc
-
std::free
-
-
异常处理:
-
std::exception
-
std::bad_alloc
-
std::runtime_error
-
-
时间日期:
-
std::chrono
-
-
输入输出流操作:
-
std::ios
-
std::iostream
-
std::stringstream
-
-
文件系统访问 (C++17):
-
std::filesystem
-
-
多线程和同步 (C++11):
-
std::thread
-
std::mutex
-
std::lock_guard
-
std::condition_variable
-
-
智能指针 (C++11):
-
std::unique_ptr
-
std::shared_ptr
-
std::weak_ptr
-
-
原子操作和线程安全 (C++11):
-
std::atomic
-
std::atomic_flag
-
-
正则表达式 (C++11):
-
std::regex
-
std::regex_search
-
-
元编程:
-
std::enable_if
-
std::conditional
-
-
类型特征 (C++11):
-
std::is_same
-
std::is_integral
-
std::is_floating_point
-
-
函数特性 (C++11):
-
std::function
-
std::bind
-
-
随机数生成 (C++11):
-
std::mt19937
-
std::uniform_int_distribution
-
-
容器访问:
-
std::begin
-
std::end
-
std::rbegin
-
std::rend
-
第2章:数据类型
语法: 数据类型 变量名 = 变量初始值
int a = 10; 数据类型存在的意义:为了给变量分配合适的内存空间。(合适内存空间,不会造成内存浪费)
数据类型 | 占用空间 |
---|---|
short | 2字节 |
int | 4字节 |
long | win为4字节,linux为4字节 |
longlong | 8字节 |
2.1sizeof关键字
作用:利用sizeof可以获得数据类型占用的内存空间大小,代码如下:
short num1=10;
cout<<"short 占用的内存空间大小"<<sizeof(num1)<<"字节"<<endl;
2.2实型(浮点型)
作用:表示小数,包含单精度浮点数float 和 双精度浮点数double
数据类型 | 占用空间 | 有效数字范围 |
---|---|---|
float | 4字节 | 7位有效数字 |
double | 8字节 | 15—16位有效数字 |
下面示例
int main(){ //1.单精度float //2.双精度double float f1 = 3.14f; cout<<"f1="<<f1<<endl; double d1 = 3.14; cout<<"d1="<<d1<<endl; system("pause"); return 0; }
2.3字符型变量
#include <iostream> using namespace std ; int main(){ //字符型变量创建方式 char ch=a; //字符型变量大小sizeof cout<<"字符变量所占内存空间大小:"<<sizeof(char)<<endl; system("pause"); return 0; }
大写字母”A“的ASCII值是65,小写字母的”a“的ASCII值是97
类型 | 关键字 |
---|---|
整型 | [signed] int |
无符号整型 | unsigned int |
有符号短整型 | [signed] short (int) |
无符号短整型 | unsigned short (int) |
有符号长整型 | [signed] long (int) |
无符号长整型 | unsigned long [int] |
注意事项!
不能串接使用使用关系运算符:a<b<c
在C++中,表示连续小于时,a<b&&a<c
操作符 | 功能 | 目数 | 用法 |
---|---|---|---|
& | 位逻辑“与” | 双目 | expr1 &expr2 |
| | 位逻辑“或” | 双目 | expr1 | expr2 |
^ | 位逻辑“异或” | 双目 | expr1 ^ expr2 |
~ | 位逻辑“取反” | 单目 | ~expr |
2.4条件运算符
2.4.1三目运算符
形式: <表达式1> ? <表达式2> : <表达式3> ,意思为“若表达式1为真,则执行表达式2;若为假,则执行表达式3”
2.4.2逗号运算符
逗号“,”,也是源自中运算符,称为逗号运算符,优先等级的最低,自左向右,共嗯是将两个表达式连接城一个表达式。
形式为:<表达式1>,<表达式2>,<表达式3>....<表达式n>
2.4.3类型转换
规则:若参与运算的类型不同,则先转换成同一类型,然后进行运算。赋值时,一般赋值符号右变量的类型转换成左变量的类型。转换按数据由低到高顺序执行,确保数据精度不降低。
2.5条件判断语句
特别注意 if--else if结构:
if(表达式1) 语句1; else if(表达式2) 语句2; ... else if (表达式m) 语句m; else 语句n;
switch - case 结构
switch (表达式){ case常量表达式1://判断,成立,执行语句1;不成立,跳转表达式2 语句1;//上述常量表达式1成立,在这执行语句1 break; case常量表达式2://判断,成立,执行语句2;不成立,跳转表达式3 语句2;//上述常量表达式2成立,在这执行语句2 break; ... case常量表达式n: 语句n; break; default: 语句n+1; break; }
第3章:函数
函数参数与返回值:表达式类型必须与函数的返回值类型相同,或者是能够隐式转换成函数有的返回值类型。
int add(int x, int y){ return(x+y); }
如果返回值是 void 类型的函数,想要在程序执行某个位置是可以推出,可以通过return 语句实现。
void OutPut(int x){ if (x<0) return ; else cout<<"x的值是:"<< x << endl; }
不返回函数值的函数,可以明确定义为“空类型”,标识符为“void”
void ShowMessage(){ cout<<"这是一个" }
3.1形参与实参
错误表达方式:
int GetMax(int x, int y = 10,int z) { /*codes*/ }
正确表达方式:
int GetMax(int x, int y,int z = 10) { /*codes*/ } //或者下面一种方式 int GetMax(int x, int y = 10, int z = 10) { /*codes*/ }
总结:如果某一形参有默认值,那么其后面的所有参数都需要有默认值!
3.2函数调用
/*包含头文件*/ int MAX(int x, int y);//开头声明函数 int MAX(int x , int y )//定义函数 { return x>y?x:y; } void main() //调用函数 { int larger = MAX(2,3); }
3.3变量作用域
在程序中,局部变量和全局变量的名称可以相同,但是在函数内,局部变量的值会覆盖全局变量的值。
//示例 #include <iostream> using namespace std; // 全局变量声明 int g = 20; int main () { // 局部变量声明 int g = 10; cout << g; return 0; }
此时输出结果为:10
3.4 函数重载(重写)
允许在同一作用域中的某个**函数和运算符指定多个定义,分别称为函数重载和运算符重载。
函数重载
在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。
#include <iostream> using namespace std; class printData //声明一个类PrintData来封装重载函数,虽然是封装 ,但是预留一个public接口允许外界访问 { public: // 设定访问级别,指定类成员是公开的 void print(int i) { cout << "整数为: " << i << endl; } void print(double f) { cout << "浮点数为: " << f << endl; } void print(char c[]) { cout << "字符串为: " << c << endl; } }; int main(void) { printData pd; // 输出整数 pd.print(5); // 输出浮点数 pd.print(500.263); // 输出字符串 char c[] = "Hello C++"; pd.print(c); return 0; }
函数重写
-
定义:函数重写发生在继承体系中,派生类提供了与基类中具有相同名称、相同参数列表的函数。
-
目的:允许派生类改变或扩展基类中虚函数的行为。
-
基类中的虚函数:为了使函数可以被重写,基类中的函数需要声明为虚函数(使用
virtual
关键字)。 -
运行时解析:运行时多态,编译器在运行时根据对象的实际类型来确定调用哪个函数。
函数重载与函数重写的区别:
-
作用域:重载发生在同一个类内,而重写发生在基类和派生类之间。
-
参数匹配:重载要求参数列表不同,而重写要求参数列表与基类中的虚函数完全相同。
-
虚函数:重写通常与虚函数一起使用,而重载不涉及虚函数的概念。
-
多态性:重载是编译时多态,重写是运行时多态。
-
访问控制:在重写时,派生类的函数访问级别不应低于基类中被重写的函数。
class Shape { public: virtual void draw() { std::cout << "Drawing a shape" << std::endl; } }; class Circle : public Shape { public: void draw() override { std::cout << "Drawing a circle" << std::endl; } };
3.5运算符重载
允许程序员为自定义类型定义运算符的行为。运算符重载通过函数重载实现
运算符重载函数的语法如下:
[ReturnType] operator[operator](参数列表...);
汽车轮子的运算符重载的例子
class Car { //声明一个Car类 public: int wheels; // 轮子数量 // 构造函数 Car(int w) : wheels(w) {} // 重载加法运算符,非成员函数形式 friend Car operator+(const Car& a, const Car& b) { return Car(a.wheels + b.wheels); } }; Car car1(4); // 创建一个有4个轮子的车 Car car2(3); // 创建一个有3个轮子的车 Car car3 = car1 + car2; // 使用重载的加法运算符,car3 将有 7 个轮子
3.6内联函数
通过inline关键字可以把函数定义为内联函数,通常在头文件下方进行定义
声明和定义如下:
inline 返回类型 函数名(参数列表) { // 函数体 }
示例
inline int max(int a, int b) { return a > b ? a : b; } int main() { int x = 5, y = 10; int result = max(x, y); // 这里 max 函数可能会被内联展开 return 0; }
解释内联函数在此段代码的作用:利用 inline关键字声明一个 max 函数,在
main函数中调用内联函数max,编译器将max函数代码直接展开到调用点。
3.7虚函数与实函数
虚函数(Virtual Functions):
-
多态性:虚函数是实现多态性的关键。它们允许派生类重写(Override)基类的函数,使得同一个函数调用根据对象的实际类型而表现出不同的行为。
-
基类指针或引用:虚函数通常通过基类的指针或引用被调用,这样可以根据指向的对象的实际类型来确定调用哪个函数。
-
虚函数表:C++通过虚函数表(VTable)机制来支持虚函数。每个有虚函数的类都有一个虚函数表,存储了虚函数的地址。
-
动态绑定:虚函数支持动态绑定(Dynamic Binding),即在运行时确定调用哪个函数。
-
声明方式:在基类中使用
virtual
关键字声明函数,然后在派生类中重写它。 -
纯虚函数:如果虚函数没有实现,它可以被声明为纯虚函数(使用
= 0
),这样的类成为抽象类,不能被实例化。
class Base { public: virtual void show() { std::cout << "Base show" << std::endl; } };
实函数(Non-Virtual Functions,或称为 Concrete Functions):
-
单一行为:实函数在编译时绑定,总是调用其所属类定义的函数,不考虑对象的实际类型。
-
直接调用:实函数可以直接通过对象、指针或引用调用。
-
没有虚函数表:实函数不使用虚函数表,因此调用效率可能略高于虚函数。
-
覆盖:如果派生类中有一个与基类同名的实函数,它会隐藏(而不是重写)基类中的同名虚函数。
-
声明方式:不需要使用
virtual
关键字,这是默认的行为。
class Base { public: void display() { std::cout << "Base display" << std::endl; } };
使用场景:
-
虚函数:当你需要在派生类中改变函数的行为,或者当你使用多态性时,应该使用虚函数。
-
实函数:当你希望函数在所有类中表现相同的行为,或者当你不关心对象的动态类型时,应该使用实函数。
第4章:变量
变量的存储类别:auto,static,register,extern
4.1 auto变量
{ int i,j,k; }
{ auto int i,j,k; }
特点:1.自动变量的作用域仅限于定义该变量的个体内“{}”
2.自动变量属于动态存储方式
3.不同个体允许使用同名的变量而不会因混淆造成报错
4.2 static变量
static int a, int b ;
特点:1.静态变量在函数内定义,在程序退出时释放
2.静态变量的作用域与自动变量相同,在哪个{}内定义,就在哪生效
3.编译器给静态变量赋值0
4.3 register变量
寄存器变量属于动态存储方式。凡是需要静态存储方式的变量就不能定义为寄存器变量
第5章:数组与字符串
有序数据的集合称为数组。一个数组有一个统一的数组名,可以通过数组名和下标来唯一确定数组的元素。
5.1一维数组
声明形式: 数据类型 数组名[常量表达式]
示例:
int a[10]; //声明一个整型数组,下标从0-9,包含10个元素 char name[128]; //声明一个字符数组,下标从0-127,包含128个元素 float price[20]; //声明一个浮点数组,下标从0-19,包含20个元素
数组说明:1.数组名的定义规则和变量名相同
2.定义数组的常量表达式不能是变量这就意味着数组大小必须要在 编译时确定
3.数组可以动态内存分配或者使用标准库容器在运行是动态定义
//动态内存分配数组内存 ----new int n = 10; // 运行时确定的大小 int* arr = new int[n]; // 使用数组... delete[] arr; // 记得释放内存
//使用std::vector: //std::vector 是C++标准模板库(STL)中的一种容器,它可以在运行时调整 大小。 #include <vector> std::vector<int> vec; int n = 10; // 运行时确定的大小 vec.resize(n); // 使用 vector...
5.2二维数组
声明形式: 数据类型 数组名[常量表达式1] [常量表达式2]
举例
float MyArray[4][5] //声明具有4行5列的元素的浮点数组
同样,定义数组的常量表达式不能是变量
int a[i][j]; //i,j都需要声明为常量,如 int i=3,j=4
对于二维数组赋值存在的两种方法,一个是单一数组赋值,另一个是聚合方法赋值。
//单一数组元素赋值 MyArray[0][1]=12;
//聚合方法赋值 int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12} int b[3][4]={ {1,2,3,4},{5,6,7,8},{9,10,11,12}}
赋值顺序是根据行列顺序进行一一赋值
5.3字符数组
字符数组是用来存放字符数据,字符数组的一个元素存放一个字符。
同样,对字符数组也具有两种赋值方式,一个是单一数组元素赋值,另一个是聚合方法赋值。
注意:聚合赋值方式只能在数组声明的时候使用,如下!
char pWord[5]={'H','E','L','L',O} ; //此种表达方式是正确的 char pWord[5]; pWord = {'H','E','L','L','O'} //此种方法是错误的,上面一行 定义数组,下面聚合赋值没有在定义char类型字符数组时使用
同时,字符数组不能给字符数组赋值,意思可理解为一个已赋值过的字符数组不能直接给未赋值的数组进行赋值操作。如下:
char a[5]={'H','E','L','L',O}; char b[5]; a=b; //这种赋值操作是不行的,字符数组间不能直接进行赋值操作 a[0]=b[0]; //这种赋值是可以接受的
字符数组常常用来作字符串使用,作为字符要有字符串结束符“\0".
虽然上述的字符数组间不能互相进行赋值操作,但是字符串可以给字符数组赋值。例子如下:
char a[]="HELLO WORLD\0";
5.4字符串处理函数
5.4.1stract函数
-
字符串连接函数stract格式:
stract(字符数组1,字符数组2)
-
字符串连接函数stract功能
将字符数组2的字符串连接到字符数组1中的字符串的后面,并删去字符串1后的结束标志“\0”
#include <iostream> #include <string> using namespace std; void main() { char str1[30],str2[10]; //定义两个字符数组str1, str2,将str2拼接到str1后 cout<<"Please input str1:"<<endl; gets(str1); //调用gets函数,从键盘获得字符串 cout<<"Please input str2:"<<endl; gets(str2); //调用gets函数,从键盘获得字符串 stract(str1,str2);//调用stract函数进行字符串拼接 //此时拼接结束,str1已经是拼接后 cout<<"The new str1 is :" puts("str1"); //puts函数输出 return 0 ; }
特别注意:<