C++大纲
在使用c语言中的一些函数时,会报错,所以可以在c语言中的函数后加上_s表示安全。例scanf_s()。或者在前面加上#define CRTSECURE_NO_WARNINGS。
输入和输出
输入和输出的基础函数库是#include <iostream>。
输出
输出时换行,使用🎞endl和\n都可以。
变量类型
变量与常量
用#define name val在使用时是直接替换,不是使用值,如#define x 1 + 2,在使用x x时就是1+21+2。在使用const时是在定义时的前面加上就行,被修饰后的常量不允许被修改。
变量类型的大小
#include <iostream>
int main() {
std::cout << "Size of char: " << sizeof(char) << " bytes" << std::endl;
std::cout << "Size of unsigned char: " << sizeof(unsigned char) << " bytes" << std::endl;
std::cout << "Size of int: " << sizeof(int) << " bytes" << std::endl;
std::cout << "Size of unsigned int: " << sizeof(unsigned int) << " bytes" << std::endl;
std::cout << "Size of short: " << sizeof(short) << " bytes" << std::endl;
std::cout << "Size of unsigned short: " << sizeof(unsigned short) << " bytes" << std::endl;
std::cout << "Size of long: " << sizeof(long) << " bytes" << std::endl;
std::cout << "Size of unsigned long: " << sizeof(unsigned long) << " bytes" << std::endl;
std::cout << "Size of long long: " << sizeof(long long) << " bytes" << std::endl;
std::cout << "Size of unsigned long long: " << sizeof(unsigned long long) << " bytes" << std::endl;
std::cout << "Size of float: " << sizeof(float) << " bytes" << std::endl;
std::cout << "Size of double: " << sizeof(double) << " bytes" << std::endl;
std::cout << "Size of long double: " << sizeof(long double) << " bytes" << std::endl;
return 0;
}
数组
在定义数组时必须要使用常量,不能使用变量。
指针
任意数据类型的指针的大小都是占8个字节。只和操作系统有关系,64位就是8,32位就是4
指针和数组的关系
指针在指向一个数组时,那它本身就是数组的第一位,指针可以进行自增,但数组不可以,在指针进行自增运算时,指针的偏移数量就是他定义的数据类型所占的字节。
指针数组
就是全都是指针的数组。
数组指针
就是指向数组的指针。
const和指针的关系
指针常量
int * const p = &a;就是意味着这个p是一个常量,不可以被修改。但是指针所指向的内容是可以被修改的。
常量指针
就是指向常量的指针,就是const int* p = &a;指针解引用不可以修改,但指针本身可以被修改。
常量指针常量
const int* const p = &a;就是指针本身和指针所指向的数据都是不可以被修改的。
指针与函数
指针函数
就是返回值是指针的函数。
函数指针
主要作用就是在定义函数时也定义一个函数指针指向这个函数,然后在main函数中让这个指针指向这个函数体,那么这个指针就可以调用这个函数了。在让这个指针等于这个函数时,这两个的类型和参数列表一定要一样。double (*ptr) (int a, int b, int c);
函数指针类型定义
typedef void (*ftp) (int a, int b);这样定义完成后ftp就是一个类型,后期使用时可以像int a;一样去定义。
函数指针数组
就是要么在定义类型时在后面加[],要么就是定义类型后像定义数组一样去定义。
🕹️引用
引用在反汇编的代码里面其实就等同于指针常量。函数引用就是避免在传参时避免再拷贝一份。
引用可以作为函数参数进行传递,在取地址后传过去的就是地址,那么在修改时就是修改的它本身。所以说它可以传递函数的参数。
引用作为函数返回值
在返回值int& max()的int类型后面加上取地址符号就可以将返回值的地址给返回回去,
常量引用
就相当于是常量指针常量,const修饰,然后在定义和引用时都要标明。
指针引用
就是int*& s就是s本身是一个地址,然后再对s进行取地址的动作。
自定义函数
返回类型 函数名(参数列表) {
// 函数体
// 可以包含多条语句
return 返回值; // 如果返回类型不是 void,则需要返回一个值
}
#include <iostream>
// 定义一个返回两个整数之和的函数
int add(int a, int b) {
return a + b;
}
// 定义一个不返回值的函数,用于打印消息
void printMessage() {
std::cout << "Hello, World!" << std::endl;
}
int main() {
int result = add(3, 5); // 调用 add 函数
std::cout << "The result is: " << result << std::endl;
printMessage(); // 调用 printMessage 函数
return 0;
}
返回类型
返回类型没有的话就是void,有的话可以是int,double,char等参数列表
可以接收多个参数,也可以不接受参数返回值
如果返回类型不是void,则需要加上返回值。返回值的类型必须要和函数的返回类型匹配。
C嘎嘎命名空间
在C++中,命名空间(Namespace)是一种用于组织代码的机制,它可以帮助避免命名冲突。当你在不同的命名空间中定义变量、函数或类时,它们的名字可以相同而不会相互干扰。命名空间是可选的,如果代码规模小可以不用命名空间。
在C++中标准库的所有内容都位于std的命名空间中,使用函数时std::cout、std::cin,还要加上std::,比较的麻烦,使用using namespeace std;可以不需要加前面的。
假设如果有两个同名字的函数,在不同的命名空间中他们就不会冲突。如LibraryA::print和LibraryB,那么你可以通过 LibraryA::print 和 LibraryB::print 来区分它们。
namespace MyNamespace
{
int myVariable = 42;
void myFunction()
{
// 函数实现
}
}
int main() {
int value = MyNamespace::myVariable;
MyNamespace::myFunction(); //访问空间中的内容
return 0;
}
🗃运算符
在C++中没有直接进行开平方和平方的运算符。算数运算符, 低于赋值运算符中的=。交换时可以使用逗号运算符,如tmp = x, x = y, y = tmp。
在考察时主要的难点就是🫚运用“/”和“%”符号的考察,因为这两个符号比较有迷惑性。
还有一个三目运算符a > b ? a : b如果成立则是a,如果不成立则是b。支持嵌套。根据成立的条件,返回的值的类型不固定。
"select * from blocks where id='20241210111418-reaq6gk'"
⌨结构体
结构体的创建方式
直接看代码,有三种方式,创建结构体后就是在main函数中创建这个变量,在C++中定义时的struct可以直接省略不写,创建后一个一个赋值是一种方法;还有就是用Book py = { "Python编程", 1999, 10 };的方法来一次性的赋值,再就是在创建结构体后就定义一个变量名。
#include <iostream>
#include <string>
using namespace std;
// 1. 结构体定义
// struct 结构体名 { 结构体成员变量列表 };
struct Book {
string name;
double price;
int value;
}cpp;
// 2. 创建结构体
int main() {
// 2.1
Book c;
c.name = "C语言程序设计";
c.price = 39.99;
c.value = 10;
cout << c.name << ' ' << c.price << ' ' << c.value << endl;
// 2.2
Book py = { "Python编程", 1999, 10 };
cout << py.name << ' ' << py.price << ' ' << py.value << endl;
// 2.3
cpp.name = "C++零基础编程";
cpp.price = 9999999;
cpp.value = 10000000;
cout << cpp.name << ' ' << cpp.price << ' ' << cpp.value << endl;
return 0;
}
联合体
我记得郝斌老师讲过联合体,意思就是这个数据结构里面可以存储多种类型,但是只能有一种,不能同时存在多种,他的内存空间是根据在这个联合体中占空间最大的一种类型。
定义和使用分开
union DataU {
int i; // 4
double d; // 8
char s[10];// 10
};
DataU a, b, c;
定义和使用结合
union DataU {
int i; // 4
double d; // 8
char s[10];// 10
}a, b, c;
匿名:不想让别人使用
union DataU {
int i; // 4
double d; // 8
char s[10];// 10
}a, b, c;
C嘎嘎的四大内存区
四大区中的栈区和堆区与数据结构中的堆区和栈区没有关系。
代码区 (Text Segment)
用途:存储程序的可执行指令。
管理:通常是只读的,防止程序意外修改指令。
特点:
包含函数和方法的机器码。
共享代码区可以减少多进程程序的内存占用。
全局/静态区(Data Segment)
用途:存储全局变量和静态变量。
管理:程序开始时分配,程序结束时释放。
特点:
包括已初始化和未初始化两部分:
已初始化数据段:存储已初始化的全局和静态变量。
未初始化数据段(BSS段):存储未初始化的全局和静态变量,初始化为零。
变量在整个程序生命周期内存在。
栈区(Stack Segment)
用途:用于存储局部变量、函数参数和返回地址。
管理:由编译器自动管理,函数调用时分配,函数结束时释放。
特点:
内存分配速度快。
空间通常较小,过多的递归调用可能导致栈溢出。
变量的生命周期受限于函数的执行时间。
堆区(Heap Segment)
用途:用于动态内存分配。
管理:由程序员手动管理,使用new分配内存,delete释放内存。
特点:
灵活性高,可以在运行时决定内存大小。
容易出现内存泄漏和碎片化问题。
分配和释放速度比栈慢。
位运算符
面向对象
面向对象三大特性:封装、继承、多态
struct和class的区别
就是struct默认是公共的,而class默认是私有的。class如果没有任何的操作那么它本身就是私有的。在c语言中struct是没办法定义函数的,但是在C++中是可以定义函数的。
属性私有化
就是将里面的数据都设置为private,无法对这些数据进行直接的修改,而是使用提供的接口(方法、函数)来进行操作,如实现读写,只读,只写。好处是可以控制读写权限和检测数据的有效性(在函数中判断)。
占位
如果在类创建后里面没有变量大小会是1,因为类里面什么都没有,就算有函数也不会在这个类里面存储,但是又不能让这个类为0,如果为0,那不就可以无限创建喽,所以要给她一个占位。
封装
封装的语法:
class 类名 {
访问权限:
属性(成员变量)
行为(成员函数)
};
在通过类来生成对象的过程叫做实例化。
访问权限
公共权限 public
类内可以访问,类外也可以访问保护权限 protected
类内可以访问,类外不可以访问 子类可以访问私有权限 private
类内可以访问,类外不可以访问 子类不可以访问
继承
继承的语法就是。子类也叫派生类,而父类也叫基类。在构造链中,先构造的后析构。就像括号一样。继承后的子类的大小就是它本身的大小加上继承的父类的继承方式大小
class 子类 : 继承方式 父类{}
继承方式
算上在类中的权限,他们相乘就有了9种的组合方式。这是表示子类继承后的权限。
在子类和父类有同一个名称的变量时,两个变量并不会相互影响,因为两个变量的地址不一样。
多继承
class son : public basea, public baseb {
}
在定义时就是在继承的一个父类后加上一个逗号然后加上另外一个要继承的父类,在不同的父类有同名的变量时使用c.basea::m_base = 45;声明作用域来指定自己要用的是哪一个变量。
多态
函数传参是个动物,但是传入不同的参数会有不同的动作,这就叫多态。
虚函数
在函数定义时在前面加上virtual就像virtual void eat {}
静态成员
static就是相当于将自己声明的东西全局到整个类中。
静态成员变量
首先设置一个变量只作用于class,类似Hero::hzb = 100,那么当class中再声明一下static int hzb;,那么这个变量不管在哪个实例里面都是一个,取值时可以是Hero::hzb也可以是hzb.hzb。需要先声明和初始化。
静态成员函数
所有对象共享函数,而且函数只能使用静态成员函数,无法使用普通成员函数。
this指针
解决命名冲突,this指针就是指向对象本身
const修饰符
在函数前加上const就是防止函数中有修改数据的操作。
mutable修饰符
常函数不能修改数据,而这个修饰符就是用来让常函数可以修改非静态成员变量的。是在定义变量时声明。
友元 friend
在类的最上面声明函数为友元,那么函数就可以访问类的私有属性。如果没有第一行的声明,那么在访问实例的数据时就回出错。也可以是类。还可以是成员函数,成员函数在声明时可以把作用域加上。
class people {
friend void firendvisit(people* p);
friend class peoplefriend;
friend void peoplefriend::visitAll(people* p);
public:
people() {
m_house = "别墅";
m_car = "跑车";
}
private:
string m_car;
};
void friendvisit(people* p)
{
cout << "我的好朋友来访问我的" << p.m_house << endl;
cout << "我的好朋友来访问我的" << p.m_car << endl;
}