Cpp学习手册-基础学习

首先你要去网上下载对应的运行软件,先把对应的 C++ 环境配置好,配置好了我们就可以开始我们的C++ 学习之旅了。希望通过学习我们能够成为一个比较不错的 C++ 开发工程师。我也会持续更新 C++ 知识。

1. C++语法基础

当我通过 CLion 工具创建了一个新的 Project

示例

#include <iostream>int main() {std::cout << "Hello, World!" << std::endl;return 0;
}

问题

  • 这一来我就不理解了 std::cout << "Hello, World!" << std::endl; 这一句语法是什么意思?

    std::cout 是一个预定义的对象,这个对象是 std::iostream 类的一个实例。count 实际上全名为 character output的缩写。当你使用 std::cout 的时候,就是在使用一个输出流对象,它连接到输出设备,通常是你的计算机屏幕。

    接着它会插入运算符(<<)时,会将紧跟在 << 后面的表达式或字符串插入到输出流中。例如,在 std::cout << "Hello, World!"; 中,字符串 "Hello, World!" 被插入到 std::cout 对象中,然后输出到屏幕。

    std::endl 也是 <iostream> 库中的一个预定义标识符,它代表 end line,意味着结束当前行并插入一个换行符。当你在输出流中使用 std::endl 时,它不仅会插入一个换行符,还会刷新输出缓冲区,确保所有待输出的数据都被立即写入到标准输出设备上。

    刷新缓冲区是必要的,因为默认情况下,C++ 可能不会立即显示所有输出。相反,它可能会在内部缓冲输出,直到缓冲区满或遇到某些特定条件才真正写入屏幕。std::endl 确保了即时显示,这对于调试和实时输出特别有用。

  • 为什么要返回一个 0 呢?可不可以用 void main(){} ?

    返回类型:之所以返回类型是 int。这是因为操作系统期望 main() 函数返回一个整数值,这个值用于指示程序的退出状态。通常,返回 0 表示程序成功执行,非零值则表示程序执行过程中遇到了错误或异常情况。

    返回0的意义: 当 main() 函数返回0时,它告诉操作系统(或者父进程)程序已经正常终止,没有遇到任何错误。这是一个约定俗成的做法,虽然不同的系统对这个值的具体含义可能有所不同,但在大多数情况下,0被视为成功的标志。

    为什么不能用 void main(): 使用 void main() 是不正确的,因为这违反了C++标准。C++标准规定 main() 函数必须返回一个整数,这主要是为了便于操作系统或父进程判断子进程的执行结果。如果你在某些编译器上看到 void main() 能够编译通过,那是因为编译器可能提供了非标准的扩展,允许这种用法,但这并不符合C++标准,也不可移植。在严格遵循标准的编译器或环境下,void main() 将会导致编译错误。

    argcargv 参数: 虽然在最简单的程序中,main() 可能只被定义为 int main(), 更常见的形式是 int main(int argc, char *argv[])int main(int argc, char **argv). 这两个参数允许程序接收来自命令行的参数。argc 表示参数的数量(包括程序名称本身),argv 是一个指向字符串数组的指针,其中每个字符串都是一个命令行参数。

变量和数据类型

不同的数据类型:

int, float, double, char, bool, string等。

/*** 变量和数据类型* @return*/
int main() {int age = 25;float height = 1.82f;double pi = 3.14159265358979323846;char grade = 'A';bool isStudent = true;std::string name = "John Doe";std::cout << name << std::endl;std::cout << "Name: " << name << ", Age: " << age << std::endl;std::cout << "height: " << height << ", pi: " << pi << std::endl;std::cout << "grade: " << grade << ", isStudent: " << isStudent << std::endl;return 0;
}

输出

在这里插入图片描述

这里面需要注意的是 string 的变量的运用。

声明和初始化变量:

其实初始化变量也是很简单的,对于变量来说无非就是全局变量和局部变量。

全局变量一般都定义在外部,初始化的话直接赋值即可。

局部变量一般定义在函数内部,初始化也很简单,直接赋值即可。

举例

#include <iostream>int globalVar = 10; // 全局变量的定义和初始化int main(){int localVar = 5; // 局部变量的定义和初始化std::cout << "全局变量:" << globalVar << std::endl; // 输出:全局变量:10std::cout << "局部变量:" << localVar << std::endl; // 输出:局部变量:5return 0;
}

变量的作用域和生命周期:

决定了变量在哪里可被访问,而生命周期则确定了变量存在的时间。

  • 局部变量:在函数内声明的变量,作用域仅限于该函数,生命周期在函数执行完毕后结束。
  • 全局变量:在所有函数外声明的变量,作用域贯穿整个程序,生命周期从程序开始到程序结束。
  • 静态局部变量:在函数内声明但具有static关键字的变量,作用域限于函数,但生命周期是整个程序。

举例

#include <iostream>void scopeLifecycle (int& age){static int number = 0; // 静态局部变量number++;age++;std::cout << "静态局部变量:" << number << std::endl;std::cout << "函数的实参:" << age << std::endl;
}int main(){int localVar = 10;scopeLifecycle(localVar);scopeLifecycle(localVar);std::cout << "外部函数变量: " << localVar << std::endl;return 0;
}

输出结果

在这里插入图片描述

通过这里我们就可以看见对于静态局部变量来说,它的生命周期是整个程序,如果不是的话,它的值每一次都应该是 1 ,而不是 2

外部变量因为传入的时候,其实是将引用的地址传给了形参,所以导致函数内部修改时,是修改的源数据,如果不加 & 的话,我们是无法修改源数据的。最后应该打印:外部函数变量:10

控制结构

掌握条件语句:

if, else if, else

对于条件语句来说,跟我们学过的语言就是大相径庭的。直接上代码吧。

举例

#include <iostream>int main() {int age;std::cout << "请输入心理年龄: ";std::cin >> age;if (age >= 18) {std::cout << "欢迎来到大人的世界!" << std::endl;} else if (age < 18 && age >= 0) {std::cout << "你还是个宝宝!" << std::endl;} else {std::cout << "你在开玩笑!" << std::endl;}return 0;
}

输出结果

在这里插入图片描述

循环结构:

for, while, do...while ,对于循环结构的学习其实也是跟其它语言类似的,直接上代码吧。

举例

#include <vector>
#include <iostream>
int main() {int age;// 创建一个空的 vector,可以存储 int 类型的数据(动态列表)std::vector<int> numbers;do {std::cout << "请输入心理年龄(小于等于0时暂停输入): ";std::cin >> age;if (age >= 18) {std::cout << "欢迎来到大人的世界!" << std::endl;} else if (age < 18 && age >= 0) {std::cout << "你还是个宝宝!" << std::endl;} else {std::cout << "你在开玩笑!" << std::endl;}numbers.push_back(age);} while (age > 0);for (int i = 0; i < numbers.size() - 1; ++i) {std::cout << "您已输入年龄(使用for循环):" << numbers[i] << std::endl;}int i = 0;while (i < numbers.size() - 1) {std::cout << "您已输入年龄(使用while循环):" << numbers[i] << std::endl;i++;}
}

输出结果

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=C%3A%5CUsers%5C97607%5CAppData%5CRoaming%5CTypora%5Ctypora-u
ser-images%5Cimage-20240816091210276.png&pos_id=img-wN9q5STQ-1724900436681)

switch语句和break, continue控制语句:

switch:

int main(){int number;std::cout << "请输入校验的数字: ";std::cin >> number;switch (number) {case 1:std::cout << "数字为1" << std::endl;break;case 2:std::cout << "数字为2" << std::endl;break;case 3:std::cout << "数字为3" << std::endl;break;default:std::cout << "数字不是 1, 2, 3" << std::endl;}
}

输出结果

在这里插入图片描述

整体来说这个 switch 的用法也是很简单,但是这里需要注意的一点是,我们需要在每一种 case 的情况之下加入break ,要不然它会在匹配完成之后,继续执行下面 case 的代码。

输出结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

continue:

int main() {for (int i = 0; i < 5; ++i) {if (i == 2) {continue;}std::cout << "i = " << i << std::endl;}return 0;
}

输出结果

在这里插入图片描述

函数

定义和调用函数:

函数的定义

返回类型 函数名(参数类型 参数名, ...) {// 函数体...return 表达式;
}

调用

函数名(参数值, ...);

参数传递方式:值传递、引用传递:

  • 值传递:将实参的值复制给形参,这样在函数内部对参数所做的修改不会影响到实参。
  • 引用传递:通过引用传递参数,实际上是将实参的地址传递给形参,这样在函数内部对参数的修改会影响到实参。
void swapByValue(int a, int b) { // 值传递int temp = a;a = b;b = temp;
}void swapByReference(int& a, int& b) { // 引用传递int temp = a;a = b;b = temp;
}

返回值和函数重载:

int add(int a, int b) {return a + b;
}double add(double a, double b) {return a + b;
}

数组

创建和初始化数组:

数组在创建时就需要确定其大小,这是因为数组的大小是在编译时期就必须固定的。其它的使用上面来说,还是比较简单的,所以直接上代码。

  • 显式创建数组

    int arr[] = {1, 2, 3, 4, 5}; // 初始化数组(显式给出初始值)
    
  • 隐式创建数组

    int arr[5] = {1, 2, 3}; // 未初始化的元素会被自动初始化为0
    

访问和操作数组元素:

// 访问和操作数组元素
int main(){int arr[] = {10, 20, 30, 40, 50};arr[0] = 100; // 修改第一个元素int firstElement = arr[0]; // 获取第一个元素std::cout << "打印数组第一个元素:" << firstElement << std::endl;return 0;
}

多维数组的使用:

多维数组可以表示表格或多维数据集。例如,二维数组可以表示矩阵:

// 多维数组的使用
int main() {int matrix[3][3] = {{1, 2, 3},{4, 5, 6},{7, 8, 9}};// 访问元素int element = matrix[1][2]; // 获取第二行第三列的元素std::cout << "打印矩阵中第二行第三列元素:" << element << std::endl;return 0;
}

2. 指针和引用

指针

C++ 中指针的使用和 C 语言里面都是大相径庭的,都是用 *& 配合使用。

指针是一种变量,它存储的是另一个变量的地址。在 C++ 中,使用星号*来声明指针。

直接上代码

int main() {using std::cout;using std::endl;int *p; // 声明一个指向整数的指针// 给指针赋值一个变量的地址,可以使用取地址运算符 &int num = 10;p = &num; // p现在指向num的地址cout << "变量 p 存储的内容:" << p << endl;// 使用指针时,可以通过解引用运算符*来访问它所指向的变量的值cout << *p << endl;// 输出num的值,即10return 0;
}

指针算术和指针作为函数参数:

指针也是可以作为形参,但是如果直接 param+1 的话表示增加指针所指向的地址,使其指向下一个整数位置,而不是简单地增加一个字节。我们需要修改它的值的话还是需要通过 *param 去修改。

void increment(int *param){(*param)++;
}int main(){int x = 5;increment(&x);std::cout << x; // 输出6return 0;
}

动态内存分配:newdelete

newdelete 是C++中用于动态内存分配的关键字。new 用于在运行时分配内存,而 delete 用于释放不再需要的内存,以避免内存泄漏。

int *ptr = new int(10); // 分配一个整数内存并初始化为10
*ptr = 20; // 更改值
delete ptr; // 释放内存

空指针和野指针的概念:

  • 空指针:顾名思义就是指针指向了无效的内存地址,通常这一块内存地址为 NULL 。这样会导致使用这个指针的时候出现未定义行为。
  • 野指针:指向已释放或未分配内存的指针。访问野指针也会导致未定义行为,可能是程序崩溃或其他不可预测的结果。

引用

引用的声明和初始化:

引用是干什么的呢?其实它相当于一个别名,并且在其生命周期内不能重新指向其他变量。引用的声明使用 & 符号,但与取地址运算符不同:

int &ref = num; // ref现在是num的一个别名

引用作为函数参数与返回值:

引用经常用作函数参数,以避免复制大对象的成本,同时允许函数修改传入的对象:

void swap(int &a, int &b) {int temp = a;a = b;b = temp;
}

引用也可以作为函数的返回值,但要注意不要返回局部变量的引用,因为局部变量在函数结束时会被销毁。

引用与指针的区别:

  • 引用在初始化之后是不能更改的,但是指针可以。
  • 引用必须在声明时初始化,而指针可以在任何时候初始化。
  • 引用是不可能为空状态的,但是指针有可能是空的。
  • 引用更安全,因为它们不会导致悬空指针的问题。

3. 面向对象编程(OOP

面向对象编程就是一种编程范式,它是通过抽象出来 ”对象“ 来设计软件。在 C++ 中,面向对象编程的主要特性包括类和对象、封装、继承和多态。

类和对象

:只是用户定义的一种数据类型,它内部封装了属性和方法。

对象:是类的实例,每一个对象都有属于自己的属性和方法。

#include <iostream>class Circle {
private:float radius;
public:float getArea() const  {return 3.1415926 * radius * radius;}void setRadius(float r) {radius = r;}float getRadius() {return radius;}
};int main(){Circle circle;circle.setRadius(5);std::cout << "圆的半径为" << circle.getRadius() << " 面积为:" << circle.getArea() << std::endl;return 0;
}

这里我想提一下上面的细节

上面在我们的 getArea 函数中,我们的形参后面还有 const 这样一个关键字,那它有什么用呢?

  • const 关键字用于声明一个变量或者表明一个函数不会修改类的成员变量。

  • 在成员函数的上下文中,const 关键字放在函数定义的末尾,紧跟着参数列表,意味着这个成员函数是一个常量成员函数,它保证不修改任何类的非静态数据成员。

对于getArea()这样的成员函数,其主要任务是计算并返回圆的面积,而不需要修改Circle类的任何状态。

const成员函数的好处有什么呢?

  1. 提高代码的安全性:它明确地表示了函数不会修改对象的状态,这有助于防止意外修改数据。
  2. 允许对常量对象的调用:如果一个Circle对象被声明为const,那么只有它的const成员函数可以被调用。如果没有将getArea()声明为const,那么尝试在一个常量对象上调用它将导致编译错误。
  3. 优化编译器可能的优化:由于编译器知道const成员函数不会改变对象状态,它可以做出更安全的优化。

构造函数和析构函数:

构造函数的作用就是用于初始化对象。

析构函数的作用就是在对象生命周期结束时调用,用于清理资源。

class Circle {
public:Circle() { std::cout << "Circle 对象构建成功!" << std::endl; }~Circle() { std::cout << "Circle 对象销毁成功!" << std::endl; }
};

封装

公有(public)、私有(private)和保护(protected)访问修饰符:

不同的访问修饰符控制了成员的访问级别。

  • public
    • 公有成员对任何代码都是可见和可访问的,无论这些代码是在同一个文件中,还是在另一个文件或另一个类中。
    • 这是默认的继承模式,也就是说,当一个类从另一个类派生时,基类的公有成员在派生类中保持公有。
  • private
    • 私有成员只能被类的成员函数访问,不能从类的外部直接访问。
    • 私有成员对于封装非常重要,因为它们隐藏了类的实现细节,使得类的使用者不必关心这些细节。
    • 在继承中,基类的私有成员不能被派生类访问,也不能被派生类的成员函数访问。
  • protected
    • 保护成员在类的内部和派生类中都是可见和可访问的,但在类的外部不可见。
    • 这意味着派生类可以访问其基类的保护成员,但类的外部代码不可以。
    • 保护成员在实现继承关系时很有用,因为它们允许派生类访问基类的某些实现细节,同时又不让这些细节暴露给最终用户。

使用gettersetter方法:

这个在上面的 Circle 类中也是有的。 一般都是在 pubic 中定义 getXXX 方法或者 setXXX 方法。gettersetter 方法的作用就是提供了一种访问和修改私有属性的方式,增强了封装性。

继承

单继承和多继承:

C++ 当中,被继承的类被称为基类,继承的类被称为派生类。

单继承就是

// 继承:
// 单继承:
class Derived: public Circle {};
int main(){Derived derived;derived.setRadius(2);derived.getRadius();
}
// 多继承:
class Base1 {};
class Base2 {};
class MultiDerived : public Base1, public Base2 {};

虚基类和多重继承冲突解决:

对于虚基类就是为了解决多重继承冲突,它可以用来避免重复基类成员的多次实例化问题。举个例子

class Base {};
class Derived1 : virtual public Base {};
class Derived2 : virtual public Base {};
class MultipleDerived : public Derived1, public Derived2 {}; // 解决多重继承冲突

Derived1 类和 Derived2 类都继承 Base 类, MultipleDerived 类继承 Derived1 类和 Derived2 类 这样我们的MultipleDerived 类就重复继承了Base 类。因为 C++ 可以实现多继承,多继承肯定就会出现这种情况,所以引入虚基类是很有必要的。

多态

虚函数和纯虚函数:

虚函数:虚函数是一个类的成员函数,它允许在派生类中被重写,从而实现多态。

举个例子

class Animal {
private:std::string food;std::string name;
public:Animal(const std::string &f, const std::string &n) {food = f;name = n;}virtual void eat() {std::cout << name << "喜欢吃:" << std::endl;}virtual void run() = 0;virtual void getLactation() {std::cout << "种类" << std::endl;}void setFood(std::string &f) {food = f;}void setName(std::string &n) {name = n;}std::string getFood() {return food;}std::string getName() {return name;}
};class Dog : public Animal {
public:Dog(const std::string &n, const std::string &f, const std::string &l) : Animal(f, n) {lactation = l;}void eat() override {std::cout << getName() << "正在吃狗粮" << std::endl;}void run() override {std::cout << getName() << "正在奔跑" << std::endl;}void getLactation() override {std::cout << getName() << "所属种类:" << lactation << std::endl;}private:std::string lactation;
};int main() {// 使用new创建Dog对象,并通过Animal指针访问Animal *animal = new Dog("贵宾犬", "肉", "哺乳动物");animal->eat();animal->getLactation();animal->run();// 记得释放内存delete animal;return 0;
}

这里面需要注意的是

Dog(const std::string &n, const std::string &f, const std::string &l) : Animal(f, n)

派生类构造函数调用基类构造函数是通过初始化列表来完成的,而不是在构造函数体内部调用。

对于纯虚函数来说:

它是在基类中声明的虚函数,其声明形式为 virtual void run() = 0;。由于纯虚函数没有实际的函数体(即没有默认实现),任何包含纯虚函数的类都是抽象类,并且抽象类不能被实例化。这意味着你不能创建抽象类的对象。

所以当你去执行

Animal animal1= new Animal("贵宾犬", "肉");

它是会报错的。

当一个派生类从含有纯虚函数的基类继承时,为了能够实例化这个派生类,它必须提供纯虚函数的具体实现。换句话说,派生类必须重写所有基类中的纯虚函数,否则派生类也将成为一个抽象类,并且不能被实例化。

虚析构函数

在涉及多态和指针的情况下,基类应当声明虚析构函数,以确保当删除派生类的实例时,正确的析构函数被调用,避免资源泄露或未定义行为。例如:

class Base {
public:virtual ~Base() {} // 虚析构函数
};

运行时多态和静态多态:

运行时多态

通常通过虚函数实现。创建了一个指向基类的指针或者引用,但是开发者可以将衍生类赋值给这个指针,并且调用基类中的虚函数。

在运行时,C++ 会查找实际对象类型对应的函数,并调用那个版本的函数,这就是动态绑定。

#include <iostream>class Base {
public:virtual void func() {std::cout << "基类\n";}
};class Derived : public Base {
public:void func() override {std::cout << "衍生类\n";}
};int main() {Base *ptr;ptr = new Base();ptr->func();  // 输出 "基类"ptr = new Derived();ptr->func();  // 输出 "衍生类"delete ptr;return 0;
}

静态多态通常指的是函数重载。

函数重载允许你在同一个作用域内有多个同名函数,只要它们的参数列表不同。编译器在编译时就能确定调用哪个版本的函数,这是基于函数调用时所提供的参数类型和数量。

#include <iostream>void example(int x) {std::cout << "Called with int: " << x << '\n';
}void example(double x) {std::cout << "Called with double: " << x << '\n';
}int main() {example(5);      // 调用example(int)example(5.0);    // 调用example(double)return 0;
}

4. 输入输出流

标准输入输出流

使用std::cinstd::cout

std::cinstd::cout是预定义的流对象,分别用于标准输入和标准输出。使用std::cin可以从标准输入设备读取数据,而std::cout用于将数据输出到标准输出设备。

举例

int main(){int number;std::cout << "请输入数字:";std::cin >> number;std::cout << "输入数字为:" << number << std::endl;return 0;
};

格式化输出和输入:

常用方法:
  • 设置宽度setw()
  • 设置填充字符setfill()
  • 设置精度setprecision()
  • 设置浮点数格式fixedscientific
  • 设置布尔值显示boolalpha
示例代码:
#include <iostream>
#include <iomanip>int main() {int number = 42;double pi = 3.14159265358979323846;double large_number = 1234567890.123456789;std::cout << "Number: (no use function setw())"  << number << '\n';std::cout << "Number: (use function setw())" << std::setw(42) << number << '\n';// 设置填充字符为 '*'std::cout.fill('*');std::cout << "Number with fill: " << std::setw(10) << number << '\n';// 一般 fixed 和 scientific 都配合 setprecision() 方法使用// 设置了 std::fixed 和 std::setprecision(n),那么小数点后将保留 n 位数字,不论数值大小如何。// 设置了 std::scientific 和 std::setprecision(n),那么小数点后将保留 n 位数字,而数值则以科学记数法的形式显示。std::cout << std::fixed << std::setprecision(2) << "Pi (fixed): " << pi << '\n';std::cout << std::scientific << std::setprecision(2) << "Large Number (scientific): " << large_number << '\n';std::cout << "Boolean: " << std::boolalpha << true << '\n';return 0;
}
运行结果:

在这里插入图片描述

文件I/O

打开和关闭文件流:

std::ifstream

用于从文件读取数据。

std::ofstream

用于向文件写入数据。

std::fstream

结合了ifstreamofstream的功能,既可以读取也可以写入文件。

读写文本文件和二进制文件:

读写文本文件示例代码:
#include <iostream>
#include <fstream>int main(){std::ofstream out("data.txt");out << "Hello, World!\n";out.close();std::ifstream  in("data.txt");std::string line;while (getline(in, line)) {std::cout << line << '\n';}in.close();return 0;
}
读写二进制文件示例代码:
#include <iostream>
#include <fstream>struct Data {int number;double value;
};int main(){Data myData = {123,45.789};std::ofstream binaryOut("binary_data.dat", std::ios::binary); // 创建 binaryOut 对象,定义写入的文件和写入的格式。// 对我们创建的Data实例的指针进行转换为char类型,然后 binaryOut.write() 函数可以使用这个指针来写入 sizeof(Data) 字节的数据到文件中。// 这样,整个结构体 myData 的内存表示就被原封不动地写入到了文件中。binaryOut.write(reinterpret_cast<char*>(&myData),sizeof(Data));binaryOut.close();Data readData;std::ifstream binaryIn("binary_data.dat", std::ios::binary);binaryIn.read(reinterpret_cast<char*>(&readData),sizeof(Data));binaryIn.close();std::cout << "Read data: " << readData.number << ", " << readData.value << '\n';  // 输出读取的数据return 0;
}

文件定位和错误处理:

文件定位:

可以使用 seekg()seekp() 来改变文件指针的位置,以及使用 tellg()tellp() 来获取文件指针的当前位置。

#include <fstream>
#include <iostream>int main(){std::ofstream out("data.txt");out << "Hello, world!\n";out.close();std::ifstream in("data.txt");in.seekg(7); // 移动到文件的第7个字符位置char ch;in >> ch; // 读取'w'std::cout << ch << '\n'; // 输出 'w'in.close();return 0;
}
错误处理:

可以检查文件流对象的状态位来判断是否发生了错误。例如,eof() 检查是否到达文件末尾,fail() 检查是否有任何错误发生等。

#include <iostream>
#include <fstream>int main(){std::ifstream in("data.txt");if (!in) {std::cerr << "打开文件出现问题\n";return 1;}// 检查文件读取过程中的错误...while (!in.eof()) {char ch;in >> ch;if (in.fail()) {std::cerr << "读取文件出现问题\n";break;}std::cout << ch;}in.close();return 0;
}

5. 总结

上面主要从几个方面来进行阐述 C++ 的一些基础的知识和用法,包括 C++语法基础,指针和引用,面向对象编程,输入输出流

希望能对您的学习有帮助!如果有什么问题,欢迎您跟我一起交流交流!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/412630.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis中的 大/热 key问题 ,如何解决(面试版)

big key 什么是 big key? big key&#xff1a;就是指一个内存空间占用比较大的键(Key) 造成的问题&#xff1a; 内存分布不均。在集群模式下&#xff0c;不同 slot分配到不同实例中&#xff0c;如果大 key 都映射到一个实例&#xff0c;则分布不均&#xff0c;查询效率也…

自建电商网站整合Refersion教程

前言&#xff1a;   先介绍一下Refersion有啥用&#xff0c;如果你有一个自己的跨境电商独立站点&#xff0c;想找一些网红帮忙推广销售自己的商品&#xff0c;然后按照转化订单比例给网红支付佣金&#xff0c;这件事情对双方来说透明性和实时性很重要&#xff0c;Refersion就…

C++ | Leetcode C++题解之第382题链表随机节点

题目&#xff1a; 题解&#xff1a; class Solution {ListNode *head;public:Solution(ListNode *head) {this->head head;}int getRandom() {int i 1, ans 0;for (auto node head; node; node node->next) {if (rand() % i 0) { // 1/i 的概率选中&#xff08;替…

Unity URPShader支持多光源处理

//声明变体并且引用文件 #pragma shader_feature _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" //在数据结构体中声明需要使用的数据 struct Attributes {float4 posit…

五种多目标优化算法(NSGA3、MOPSO、MOGWO、NGSA2、SPEA2)性能对比,包含47个多目标测试函数,6种评价指标,MATLAB代码

一、五种多目标算法及六种评价指标简介 多目标灰狼优化算法&#xff08;MOGWO&#xff09;&#xff1a; MOGWO是由Mirjalili等人在2016年提出的&#xff0c;基于灰狼优化算法&#xff08;GWO&#xff09;的多目标版本。它引入了存档机制和改进的头狼选择方式&#xff0c;以处理…

2024-08-30作业

作业2 代码 #include <iostream>using namespace std;class Per { private: string name; int age; double* height; double* weight; public: //有参构造函数 Per(string name,int age,int height,int weight):name(name),age(age),height(new double(height)),weigh…

基于STM32开发的智能家居温度控制系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 系统初始化温度监测与显示风扇/加热器控制Wi-Fi通信与远程监控应用场景 家庭环境的智能温度管理办公楼的节能温控系统常见问题及解决方案 常见问题解决方案结论 1. 引言 随着人们对生活质量…

Flask+LayUI开发手记(六):树型表格的增删改查

树型表格的增删改查功能与数据表格的是完全一致&#xff0c;就是调用layui-form表单组件实现数据输入再提交&#xff0c;比较大的区别是树型节点的编辑&#xff0c;都需要有上级节点的输入&#xff0c;而这个上级节点的展示&#xff0c;必须是以树型方式展示出来。当然&#xf…

使用facebook开源prophet模型预测上证指数etf股价

可以图个乐&#xff0c;没有那么准确&#xff0c;可能还需要更深入的研究分析 蓝线是预测的2024年的走势&#xff0c;绿线是实际走势&#xff0c;红线是历史和未来的分界线。结果上有蛮多差异的。 # 测试预测2024年 coded by luke 伊玛目的门徒 import akshare as ak impor…

信息学奥赛一本通/openjudge Crossing River

题目 一本通题目入口 openjudge题目入口 &#xff08;注&#xff1a;由于一本通题面描述的可能有些欠缺&#xff0c;所以这里的题面采用openjudge英文翻译后的题面&#xff09; 题目分析 首先我们来看样例&#xff0c;为什么样例的结果是17呢?首先观察&#xff0c;“5”和“…

GUI编程04:课堂练习及总结

本节内容视频链接&#xff1a;6、课堂练习讲解及总结_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1DJ411B75F?p6&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 根据前三节学习到的Frame、Panel、Button知识&#xff0c;画出一下窗口界面&#xff1a; 实现代码如下…

Spring Security基于token的极简示例

1 引言 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架&#xff0c;但是用起来有点复杂&#xff0c;为了便于学习理解&#xff0c;下面将用最简洁的配置和示例&#xff0c;展示整个流程。 2 代码 创建一个spring-security…

单图生成 2D 和 3D 人物,高质量图像处理模型 CharacterGen来啦!

CharacterGen引入了一个简化的生成流程和一个图像条件的多视图扩散模型。该模型有效地将输入姿态校准到规范形式&#xff0c;同时保留输入图像的关键属性&#xff0c;从而解决了多样化姿态带来的挑战。 CharacterGen的另一个核心组成部分是基于Transformer的、可泛化的稀疏视图…

kafka 入门

kafka 有分区和副本的概念&#xff0c;partition 3 表示有3个分区&#xff0c;replication 2 表示有2个副本 通过 --describe --topic test命令可以知道 test这个 主题的分区和副本情况&#xff0c;途中的replicas 表示 其他副本分区的情况&#xff0c;如第一条&#xff0c;t…

【spring】学习笔记2:sample、boot功能和组件设计

Spring自带了一个强大的Web框架,名为Spring MVC。Spring MVC的核心 是控制器(controller)的理念。控制器是处理请求并以某种方式进行信息 响应的类。在面向浏览器的应用中,控制器会填充可选的数据模型并将请求 传递给一个视图,以便于生成返回给浏览器的HTML。在pom.xml文件…

免费批量Excel文件合并、拆分软件

软件介绍 下载地址&#xff1a;https://pan.quark.cn/s/ae860a4e2ccb 1.多个XLS或XLSX格式EXCEL文件合并&#xff0c;合并后可使用数据透视表进行相关操作。 2.自动合并多个EXCEL文件的第一个工作表&#xff0c;并汇总成一张表&#xff0c;可根据所有列标题需要指定需要的列。 …

Ethernet 测试系列(1)-- 物理层测试::IOP Test::Link-up time

车载以太网物理层IOP测试&#xff0c;即互操作性测试&#xff08;Interop- erability Tests&#xff09;&#xff0c;用于验证车载以太网PHY&#xff08;通常也称为收发器&#xff09;的可靠性和检查PHY能否在给定的有限时间内建立稳定的链路;还用于车载以太网PHY的诊断&#x…

Unity编辑器扩展之Hierarchy面板扩展

内容将会持续更新&#xff0c;有错误的地方欢迎指正&#xff0c;谢谢! Unity编辑器扩展之Hierarchy面板扩展 TechX 坚持将创新的科技带给世界&#xff01; 拥有更好的学习体验 —— 不断努力&#xff0c;不断进步&#xff0c;不断探索 TechX —— 心探索、心进取&#xff…

JavaScript学习文档(11):Window对象、本地存储、数组中一些方法、学生就业统计表案例

目录 一、Window对象 1、BOM(浏览器对象模型) 2、定时器-延时函数 3、 JS执行机制 &#xff08;1&#xff09;同步任务&#xff1a; &#xff08;2&#xff09;异步任务&#xff1a; 4、location对象 &#xff08;1&#xff09;5秒钟后跳转页面 5、navigator对象 6、…

乐城堡 JoyCastle Unity岗位笔试题

1)实现 move(GameObjct gameObject, Vector3 begin, Vector3 end, float time, bool pingpong){ } 使 gameObject 在 time 秒内&#xff0c;从 begin 移动到 end&#xff0c;若 pingpong 为 true&#xff0c;则在结束时 使 gameObject 在 time 秒内从 end 移动到 begin&#xf…