从C语言到C++(五)

从C语言到C++(五)

  • 自动类型推导
    • 尾拖返回类型
    • 类型信息推导
      • `typeid`
        • 1. 定义和基本作用
        • 2. 使用方法
        • 3. 注意事项
        • 4. 示例代码
        • 5. 关联概念:RTTI
      • `decltype`
        • 基本用法
        • 示例
        • 注意事项
        • 总结
  • 基于范围的增强for循环
    • 示例 1:使用数组
    • 示例 2:使用`std::vector`
    • 示例 3:使用`std::map`
  • 函数
    • 1. 函数重载(Overloading)
      • 调用机制
    • 2. 内联函数(Inline Functions)
      • 内联函数的作用
      • 内联函数的限制
    • 3. 引用参数(Reference Parameters)
    • 4. 默认参数(Default Parameters)
      • 默认参数
      • 占位参数
    • 5. 模板函数(Template Functions)
    • 6. 成员函数(Member Functions)

自动类型推导

在C++中,自动类型推导(Automatic Type Deduction)主要通过auto关键字实现。当你使用auto关键字声明一个变量时,编译器会根据初始化该变量的表达式的类型来自动推断出变量的类型。

以下是一些使用auto进行自动类型推导的例子:

#include <iostream>
#include <vector>int main() {// 基本类型推导auto a = 10;     // a的类型是intauto b = 3.14f;  // b的类型是float// 引用类型推导int x = 10;auto& ref_x = x; // ref_x的类型是int&,它是对x的引用// 指针类型推导int* ptr_x = &x;auto ptr_y = &x; // ptr_y的类型是int*// 复杂类型推导std::vector<int> v = {1, 2, 3, 4, 5};auto first = v.begin(); // first的类型是std::vector<int>::iterator// 初始化列表推导auto c = {1, 2, 3}; // 在C++11中,这可能会推导出std::initializer_list<int>// 但如果auto与&结合使用,则可以推导出引用到数组auto& d = {1, 2, 3}; // 错误:不能对临时对象使用引用// 但可以这样使用:int arr[] = {1, 2, 3};auto& e = arr; // e的类型是int(&)[3],即arr的引用return 0;
}

注意

  1. 使用auto可以使代码更加简洁和清晰,但也可能导致可读性降低,特别是在复杂类型的情况下。因此,在使用auto时,需要权衡代码的可读性和简洁性。
  2. auto不会推导为引用类型,除非你明确使用&。同样,它也不会推导为指针类型,除非你明确使用*&运算符。
  3. auto不能用于函数参数或模板参数的类型推导。在这些情况下,你需要明确指定类型。
  4. 在C++17中,引入了结构化绑定(Structured Bindings),它允许你使用auto来同时声明多个变量,并从元组、对、结构体等中提取值。例如:auto [x, y] = std::make_pair(1, 2);

尾拖返回类型

在C++中,尾置返回类型(Trailing Return Type)或称为后置返回类型(Postfix Return Type)是一种在函数声明或定义中指定返回类型的语法特性,它特别有用于处理模板函数中返回类型依赖于模板参数的情况。尾置返回类型允许你在函数声明或定义的参数列表之后指定返回类型。

尾置返回类型的使用语法通常与auto关键字结合,并且使用->操作符来指定返回类型。以下是一个简单的例子,展示了如何在模板函数中使用尾置返回类型:

template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {return t + u;
}

在上面的例子中,decltype(t + u)就是尾置返回类型。它告诉编译器,这个函数的返回类型是tu相加的结果类型。

不过,从C++14开始,我们可以使用auto关键字直接在函数声明中推断返回类型,而不需要显式地使用尾置返回类型:

template<typename T, typename U>
auto add(T t, U u) {return t + u;
}

编译器会根据return语句中的表达式来推断函数的返回类型。这种自动类型推断使代码更加简洁和易读。

然而,在某些情况下,尾置返回类型仍然是必要的。例如,当返回类型依赖于多个参数,或者当返回类型是一个复杂的表达式,而不仅仅是函数参数的一个简单操作时,尾置返回类型就派上了用场。此外,它还可以用于解决某些类型推导问题,特别是当涉及引用折叠(reference collapsing)和std::forward等高级模板技术时。

类型信息推导

typeid

typeid是C++中的一个操作符,它用于在运行时获取一个类型或对象的实际类型信息。以下是关于typeid的详细解释:

1. 定义和基本作用
  • typeid是C++中的一个操作符,它用于获取一个类型或对象的运行时类型信息。
  • 在程序中,当我们需要获取某个对象或变量的类型信息时,可以使用typeid操作符。
  • typeid的返回值是一个type_info类型的对象,它包含了被查询对象的类型信息和一些相关函数和属性。
2. 使用方法
  • typeid类似于sizeof这样的操作符,但不是函数。
  • typeid定义在typeinfo头文件中。
  • 可以通过typeid(变量或类型).name()来获取类型的名称,但需要注意的是,不是所有编译器都会输出如"int"、"float"等这样的类型名称。
  • typeid可以用于动态类型,也可以用于静态类型。静态类型和动态类型分别对应的是编译时和运行时的类型识别。
  • typeid多数运用于class和继承中。
3. 注意事项
  • 对于非引用类型,typeid是在编译时期识别的;只有引用类型才会在运行时识别。
  • 运行时获知变量类型名称时,可以使用typeid(变量).name(),但需要注意返回的类型名称可能因编译器而异。
4. 示例代码
#include <iostream>
#include <typeinfo>
using namespace std;int main(void) {int a;char b;unsigned char c;signed char d;cout << "a typeid =" << typeid(a).name() << endl; // 打印a的类型cout << "b typeid =" << typeid(b).name() << endl; // 打印b的类型cout << "c typeid =" << typeid(c).name() << endl; // 打印c的类型cout << "d typeid =" << typeid(d).name() << endl; // 打印d的类型return 0;
}
5. 关联概念:RTTI
  • typeid与RTTI(Run-Time Type Identification,运行时类型识别)紧密相关。RTTI使程序能够获取由基类指针或引用所指向的对象的实际派生类型。

总结:typeid是C++中用于在运行时获取类型信息的关键字,通过它我们可以获取一个类型或对象的实际类型信息,这在处理复杂的类型系统或进行类型检查和转换时非常有用。

decltype

decltype 是 C++11 引入的一个关键字,用于在编译时从表达式中推导类型。decltype 的主要作用是在编译时检查一个表达式并返回该表达式的类型,而不实际计算该表达式。这使得 decltype 在模板元编程、自动类型推导和函数返回类型推导等场景中特别有用。

基本用法

decltype 的基本语法如下:

decltype(expression) var;

这里 expression 是一个表达式,decltype 会根据这个表达式的类型来推导 var 的类型。

示例
  1. 基本类型推导
int x = 10;
decltype(x) y = 20; // y 的类型是 int
  1. 表达式推导
int a = 10, b = 20;
decltype(a + b) sum = a + b; // sum 的类型是 int
  1. 引用类型推导
int& ref = a;
decltype(ref) another_ref = b; // another_ref 是 int& 类型,它引用 b
  1. 函数返回类型推导
template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {return t + u;
}// 或者在 C++14 及以后使用自动返回类型推导
template<typename T, typename U>
auto add(T t, U u) {return t + u;
}

在上面的例子中,decltype(t + u) 用于推导函数 add 的返回类型,它依赖于参数 tu 的类型以及它们相加的结果类型。

注意事项
  • decltype 并不计算表达式的值,它只是检查表达式的类型。
  • decltype 用于未声明的变量或表达式时,编译器会报错。
  • 如果表达式是一个左值(如变量、数组元素、结构体的成员等),decltype 会推导出一个引用类型。如果表达式是一个右值(如字面量、临时对象等),则推导出的类型不是引用。
  • 可以通过添加括号来改变 decltype 的推导行为。例如,decltype((variable)) 总是推导出一个引用类型,即使 variable 是一个右值。
总结

decltype 是 C++ 中的一个强大工具,它允许程序员在编译时从表达式中推导类型,而无需显式指定。这使得代码更加灵活和易于维护,特别是在处理复杂类型和模板元编程时。

基于范围的增强for循环

在C++11及更高版本中,引入了基于范围的for循环(Range-based for loop),也被称为"for-each"循环,用于简化对容器(如数组、std::vectorstd::liststd::set等)或其他可迭代对象的遍历。

基于范围的for循环的语法如下:

for (declaration : range) {// 循环体
}

在这里,declaration是每次循环时从range中提取出的元素的声明,而range是一个可迭代的对象,比如一个容器。

下面是一些基于范围的for循环的示例:

示例 1:使用数组

#include <iostream>int main() {int arr[] = {1, 2, 3, 4, 5};for (int num : arr) {std::cout << num << ' ';}std::cout << std::endl;return 0;
}

示例 2:使用std::vector

#include <iostream>
#include <vector>int main() {std::vector<int> vec = {1, 2, 3, 4, 5};for (int num : vec) {std::cout << num << ' ';}std::cout << std::endl;return 0;
}

示例 3:使用std::map

当遍历std::map时,你可以同时获得键和值。

#include <iostream>
#include <map>int main() {std::map<std::string, int> myMap = {{"apple", 1}, {"banana", 2}, {"cherry", 3}};for (const auto& pair : myMap) {std::cout << pair.first << ": " << pair.second << std::endl;}return 0;
}

在这个例子中,pair是一个std::pair<const std::string, int>类型的对象,其中first是键,second是值。我们使用const auto&来避免不必要的拷贝,并提高性能。

基于范围的for循环在C++编程中非常有用,因为它使代码更简洁,同时仍然保持了很好的可读性。这种循环特别适合于只读迭代,当你不需要直接访问迭代器的时候。如果你需要修改迭代器(例如,在遍历过程中删除元素),那么你可能需要使用传统的迭代器循环。

函数

从C语言过渡到C++时,函数的概念在很多方面是相似的,但C++为函数提供了更多的特性和灵活性。以下是C和C++中函数的一些主要差异和C++特有的功能:

1. 函数重载(Overloading)

在C++中,函数重载(Function Overloading)是一种特性,它允许我们为同一个函数名定义多个版本,只要这些版本的参数列表(参数类型、参数数量或参数顺序)不同即可。编译器会根据调用时提供的参数类型和数量来确定调用哪个版本的函数。

下面是一个关于函数重载的例子:

#include <iostream>
#include <string>// 第一个版本的print函数,接受一个整数参数
void print(int x) {std::cout << "Printing an integer: " << x << std::endl;
}// 第二个版本的print函数,接受一个浮点数参数
void print(double x) {std::cout << "Printing a double: " << x << std::endl;
}// 第三个版本的print函数,接受一个字符串参数
void print(const std::string& s) {std::cout << "Printing a string: " << s << std::endl;
}// 第四个版本的print函数,接受两个整数参数
void print(int x, int y) {std::cout << "Printing two integers: " << x << " and " << y << std::endl;
}int main() {print(10);           // 调用第一个版本的print函数print(10.5);         // 调用第二个版本的print函数print("Hello");      // 调用第三个版本的print函数print(10, 20);       // 调用第四个版本的print函数return 0;
}

在上面的例子中,我们定义了四个名为print的函数,每个函数都接受不同类型的参数或不同数量的参数。在main函数中,我们根据提供的参数类型和数量来调用不同版本的print函数。

函数重载必须满足以下条件:

  1. 函数名必须相同。
  2. 参数列表必须不同(可以是参数类型、参数数量或参数顺序不同)。
  3. 返回类型不参与函数重载的判定(即返回类型不同不能构成重载)。

注意:在C++中,函数重载是通过参数列表来区分的,而不是通过函数名或返回类型。因此,你不能仅通过改变函数名或返回类型来重载一个函数。

此外,还有一个需要注意的点是,当使用默认参数时,重载函数可能会产生歧义。例如,如果你有一个接受一个整数参数的函数和一个接受两个整数参数(其中第二个参数有默认值)的函数,那么只传递一个整数参数给这两个函数时,编译器可能无法确定要调用哪个函数。因此,在设计函数重载时要避免这种情况。

调用机制

在C++中,函数重载的调用机制主要依赖于函数的名称和参数列表(即参数的类型、数量和顺序)。当编译器遇到对某个函数的调用时,它会根据提供的参数来确定应该调用哪个重载版本。这个过程称为名称查找(Name Lookup)和重载解析(Overload Resolution)。

以下是重载函数调用机制的基本步骤:

  1. 名称查找(Name Lookup)

    • 编译器首先会在当前作用域中查找与调用名称匹配的函数声明。
    • 如果在当前作用域中找不到匹配的函数声明,编译器会继续在包含当前作用域的作用域中查找,直到找到全局作用域。
    • 这个过程会找到所有与调用名称匹配的函数声明,包括所有重载版本。
  2. 重载解析(Overload Resolution)

    • 一旦编译器找到了所有与调用名称匹配的函数声明,它就会开始重载解析过程。
    • 重载解析的主要任务是确定应该调用哪个重载版本的函数。这是通过比较调用时提供的参数与每个重载版本的参数列表来完成的。
    • 编译器会尝试将提供的参数与每个重载版本的参数列表进行匹配。匹配的过程包括类型转换(如果需要的话),但通常编译器会优先考虑那些不需要类型转换的匹配。
    • 如果某个重载版本的参数列表与提供的参数完全匹配(即不需要任何类型转换),那么这个版本就是最佳匹配,编译器将调用这个版本的函数。
    • 如果没有找到完全匹配的版本,编译器会尝试找到最接近的匹配。这通常涉及到类型转换和类型提升。编译器会考虑所有可能的类型转换,并选择一个“最佳”的匹配。
    • 如果存在多个同样“好”的匹配(例如,两个函数都需要相同的类型转换),编译器就会报错,因为这种情况下无法确定应该调用哪个函数。这被称为“重载解析失败”。
  3. 调用函数

    • 一旦确定了要调用的函数版本,编译器就会生成代码来调用该函数。这通常涉及到将参数传递给函数,并执行函数的代码。

需要注意的是,函数重载只与参数列表有关,与函数的返回类型无关。也就是说,你不能仅仅通过改变函数的返回类型来重载一个函数。此外,函数重载也与函数的定义位置无关,只要函数声明在调用之前可见即可。

另外,还需要注意的是,函数重载并不改变函数的名称或参数列表。它只是允许你使用相同的函数名来定义多个具有不同参数列表的函数。在编译时,编译器会根据提供的参数来确定应该调用哪个版本的函数。在运行时,函数重载对程序的行为没有任何影响。

2. 内联函数(Inline Functions)

C++支持内联函数,这是一种建议编译器将函数调用替换为函数体本身的机制。这可以减少函数调用的开销,但可能会增加代码大小。在C语言中,内联函数不是语言的一部分,但编译器可能提供特定的扩展来支持它。

// C++ 示例
inline int max(int a, int b) {return (a > b) ? a : b;
}

内联函数的作用

内联函数(Inline Functions)在C++中主要起到以下作用:

  1. 减少函数调用的开销:当函数被声明为内联时,编译器会尝试在调用点将函数体直接插入,而不是进行常规的函数调用(即压栈、跳转、返回)。这样做可以消除函数调用的开销,从而提高程序的执行效率。对于小型且频繁调用的函数,这种开销减少尤为显著。

  2. 提高代码执行效率:由于内联函数在调用点直接插入函数体,可以减少因函数调用而产生的额外开销,如参数传递、栈帧创建和销毁等。因此,内联函数可以提高代码的执行效率。

  3. 消除函数调用的副作用:在某些情况下,函数调用可能会产生副作用,如修改全局变量或静态变量的值。而内联函数可以避免这种副作用,因为其在编译时展开,不会进行实际的函数调用。

  4. 支持类中的成员函数:在面向对象编程中,类的成员函数经常需要被频繁调用。将类的成员函数声明为内联函数可以减少因函数调用而产生的额外开销,从而提高程序的性能。此外,内联函数还可以保证类的封装性和隐藏性,因为只有在类的内部才能看到函数的实现细节。

  5. 提高可读性:对于某些简单的函数,将其声明为内联函数可以使代码更加紧凑和易于阅读。这是因为内联函数在调用点直接插入函数体,可以避免过多的函数调用和跳转,使代码结构更加清晰。

  6. 优化性能:在某些情况下,编译器可能会根据上下文和性能分析的结果自动将某些函数内联化。即使这些函数没有被显式声明为内联函数,编译器也会根据性能优化的需要进行内联展开。这进一步体现了内联函数在优化性能方面的作用。

需要注意的是,虽然内联函数可以提高程序的执行效率,但过度使用内联函数可能会导致代码膨胀和降低缓存效率。因此,在编写和使用内联函数时应该权衡利弊,根据具体情况进行选择。同时,也需要注意编译器对内联函数的支持程度和限制条件。

内联函数的限制

  1. 函数体复杂性

    • 内联函数的函数体不能含有复杂的结构控制语句,如whilefordo-whileswitch等循环和条件语句。如果内联函数中包含这些复杂的控制语句,编译器通常会将其视为普通函数处理,不进行内联展开。
    • 递归函数不能被声明为内联函数,因为递归函数需要函数调用栈的支持,而内联函数在编译时展开,不保留函数调用栈信息。
  2. 函数体大小

    • 内联函数通常适用于小型函数,如1-5行代码的小函数。过大的函数体可能会导致代码膨胀,降低程序的执行效率。
  3. 不能包含特定语句

    • 内联函数中不能说明数组(虽然这不是绝对的,但某些编译器可能会有限制)。
    • 内联函数中不能有过多的条件判断语句,因为这会降低内联的效果。
    • 不能对函数进行取址操作,因为内联函数没有独立的函数地址。
  4. 定义位置

    • 为了确保内联函数在所有调用它的地方都能被正确展开,通常需要将内联函数的定义放在头文件中。
  5. 编译器建议性

    • 内联函数是建议性的,而非强制性的。即使函数被声明为内联,编译器也有权选择忽略这个建议,不将函数内联化。这通常发生在函数体过大、过于复杂,或者编译器认为内联化不会带来性能提升的情况下。
  6. 性能考虑

    • 虽然内联函数可以减少函数调用的开销,但过度使用内联函数可能会导致代码膨胀,降低缓存命中率,反而降低程序的运行效率。因此,在使用内联函数时应该权衡利弊,根据具体情况进行选择。

综上所述,内联函数虽然可以提高程序的运行效率,但也有一些限制和需要注意的地方。在编写和使用内联函数时,应该根据具体情况进行权衡和选择。

3. 引用参数(Reference Parameters)

C++支持引用参数,允许函数直接操作传递给它的变量的原始数据,而不是其副本。这可以避免不必要的复制操作,提高效率。在C语言中,你只能通过指针来模拟这种行为。

// C++ 示例
void modify(int& x) { // 引用参数x = 10;
}int main() {int y = 5;modify(y); // y 的值现在为 10return 0;
}

4. 默认参数(Default Parameters)

在C++中,可以为函数参数提供默认值。如果在调用函数时没有提供这些参数的值,则使用默认值。这在C语言中是不可能的。

// C++ 示例
void greet(std::string name = "World") {std::cout << "Hello, " << name << "!" << std::endl;
}int main() {greet(); // 输出 "Hello, World!"greet("Alice"); // 输出 "Hello, Alice!"return 0;
}

默认参数

默认参数是C++中函数的一种特性,允许在函数调用时省略某些参数,此时将使用这些参数的默认值。以下是关于默认参数的详细解释:

  1. 定义与使用

    • 默认参数指的是在函数声明时给函数参数指定一个默认值。
    • 如果调用函数时没有给这个参数传入实参,则使用默认值;如果传入了实参,则替换掉默认值。
  2. 语法规则

    • 默认参数只能从最右侧变量依次赋值,即如果一个参数有默认值,则它右边的所有参数都必须有默认值。
    • 当函数的声明和实现分开时,需要在声明时指定默认值,实现时不能再次指定。
  3. 示例
    假设我们有一个函数print_int,它接受一个整型参数i,并有一个默认值-1

    void print_int(int i = -1) {std::cout << "i=" << i << std::endl;
    }
    

    调用这个函数时,我们可以选择是否传入参数:

    print_int();  // 输出:i=-1
    print_int(10); // 输出:i=10
    
  4. 注意事项

    • 不要过度依赖默认参数,因为它们可能会使函数的使用变得模糊,增加维护成本。
    • 当函数的参数较多,且很多参数都有默认值时,应该考虑使用其他方法(如结构体或类)来组织这些参数,以提高代码的可读性和可维护性。
  5. 优点

    • 提高了函数的灵活性,允许在函数调用时省略某些参数。
    • 可以简化函数调用,减少代码冗余。
  6. 缺点

    • 如果过度使用默认参数,可能会导致函数接口变得复杂和难以理解。
    • 如果在函数实现中再次指定了默认参数的值(当声明和实现分开时),将会导致编译错误。
  7. 与其他特性的关系

    • 默认参数可以与函数重载结合使用,以增加函数的多样性。
    • 内联函数也可以使用默认参数,但内联函数的主要目的是提高程序性能,而默认参数则主要用于提高函数的灵活性。

占位参数

定义函数时,还可以给函数提供占位参数

  • 占位参数只有参数类型,而没有参数名
  • 在函数体内部无法使用占位参数
  • 占位参数也可以指定默认参数
void func(int a,int = 0)
{cout<<a<<endl;
}
func(2);

5. 模板函数(Template Functions)

C++支持模板函数,允许你编写与类型无关的代码。编译器在编译时根据提供的类型信息实例化模板函数。这在C语言中是不可用的。

// C++ 示例
template <typename T>
T max(T a, T b) {return (a > b) ? a : b;
}int main() {int i = max(3, 5); // 调用 max<int>(3, 5)double d = max(3.14, 2.71); // 调用 max<double>(3.14, 2.71)return 0;
}

6. 成员函数(Member Functions)

在C++中,你可以定义类的成员函数,这些函数与类的特定实例相关联。这与C语言中的函数完全不同,C语言中的函数是全局的或静态的。

// C++ 示例
class MyClass {
public:int x;MyClass(int value) : x(value) {}// 成员函数void printValue() {std::cout << "x 的值为: " << x << std::endl;}
};int main() {MyClass obj(10);obj.printValue(); // 输出 "x 的值为: 10"return 0;
}

这些只是C++函数相对于C语言函数的一些主要差异和新增功能。C++还提供了许多其他特性和功能,如异常处理、类和对象、继承、多态等,这些都使C++成为一种功能强大的编程语言。

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

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

相关文章

定个小目标之刷LeetCode热题(21)

这是道技巧题&#xff0c;利用了 &#xff08;num - 1&#xff09;% n 计算下标的形式来将数组元素与数组索引产生映射关系&#xff0c;代码如下&#xff0c;可以看下注释 class Solution {public List<Integer> findDisappearedNumbers(int[] nums) {int n nums.lengt…

【Starrocks docker-compose部署】

一、docker-compose部署starrocks 官方的docker-compose地址:docker-compose地址 version: "3.9" services:starrocks-fe-0:image: starrocks/fe-ubuntu:latesthostname: starrocks-fe-0container_name: starrocks-fe-0command:- /bin/bash- -c- |/opt/starrocks/f…

微信小程序地图

微信小程序实现地图功能可以通过使用腾讯地图 API 实现。以下是一个简单的示例&#xff0c;实现在微信小程序中显示地图并标记一些地点的代码&#xff1a; // 在 wxml 文件中引入 map 组件 <view class"map-container"><map id"map" latitude&qu…

Java连接池的原理和例子

Java连接池的原理是为了优化数据库连接的管理&#xff0c;通过复用和共享数据库连接来提高应用程序的性能和响应速度。以下是Java连接池原理的详细解释&#xff1a; 初始化连接池&#xff1a; 在应用程序启动时&#xff0c;连接池会根据配置的参数&#xff0c;创建一定数量的…

pdf格式转成jpg图片,pdf格式如何转jpg

pdf转图片的方法&#xff0c;对于许多人来说可能是一个稍显陌生的操作。然而&#xff0c;在日常生活和工作中&#xff0c;我们有时确实需要将pdf文件转换为图片格式&#xff0c;以便于在特定的场合或平台上进行分享、展示或编辑。以下&#xff0c;我们将详细介绍一个pdf转成图片…

父亲节 | 10位名家笔下的父亲,读懂那份孤独而深沉的父爱

Fathers Day 母爱如水&#xff0c;父爱如山。 相对于母爱的温柔&#xff0c;父亲的爱多了几分静默和深沉。 读完10位名家笔下的父亲&#xff0c;我们就会明白&#xff0c;到底亏欠了父亲多少。 不要让自己有“子欲养而亲不待”的后悔和遗憾&#xff0c; 多给父亲一些爱的表示&a…

敏捷=996/007?现实是……

最近几年&#xff0c;大部分公司都在招聘信息里宣扬拥抱敏捷开发&#xff0c;敏捷管理&#xff0c;让人一看就觉得高大上&#xff0c;殊不知&#xff0c;不知道坑了多少纯真烂漫的应届生。 他们满怀期待地步入职场&#xff0c;以为凭借着自己985&#xff0c;211的金字招牌&…

mySql的事务(操作一下)

目录 1. 简介2. 事务操作3. 四大特性4. 并发事务问题5. 脏读6. 不可重复读7. 幻读事务隔离级别参考链接 1. 简介 事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位&#xff0c;事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求&#xff0c;即这些操作…

使用Java Spring Boot生成二维码与条形码

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

牛客 第二十届西南科技大学ACM程序设计竞赛(同步赛):祖玛

题目描述 wzy 在玩一种很新的祖玛。 给定一个仅包含 小写字母 的字符串 sss , sss 由 mmm 个不同的小写字母组成&#xff0c;每个字母代表一种小球&#xff0c;在消去时会获得 相应 的分数&#xff1a; 两个及以上 相同的小球相碰就会消失&#xff08;在发射小球前因为无相碰&…

dead--栈队列

创建链表 分别用头插法和尾插法创建并输出带附加头结点的单链表。 头插法是指每个新元素都插入到链表的最前面&#xff0c;即头结点和链表第一个元素之间&#xff1b; 尾插法指的是每个新元素都插入到链表的最后面。 输入描述 输入&#xff1a;一组整数&#xff0c;以EOF为结束…

ffmpeg解封装rtsp并录制视频-(2)使用VLC模拟一个rtsp服务器并用ffmpeg解封装该rtsp流

VCL模拟服务器并打开播放该视频文件&#xff1a; - 准备好一个mp4文件&#xff0c;打开vlc软件 - 选择“媒体”》“流” - 添加一个mp4文件 - 点击下方按钮选择“串流” - 下一步目标选择rtsp 点击“添加” - 端口默认8554 - 路径设置 /test - 用…

代码随想录算法训练营Day37|56.合并区间、738.单调递增的数字、968.监控二叉树

合并区间 56. 合并区间 - 力扣&#xff08;LeetCode&#xff09; 和之前的思路类似&#xff0c;先创建一个ans二维数组&#xff0c;创建start和end来指明添加进入ans数组的区间下标&#xff0c;先对数组按照首元素排序从小到大排序后&#xff0c;根据当前元素是否小于下一个元…

【three.js】自定义物体形状BufferGeometry

目录 一、认识缓冲类型几何体BufferGeometry 二、将各个顶点连线 一、认识缓冲类型几何体BufferGeometry threejs的长方体BoxGeometry、球体SphereGeometry等几何体都是基于BoxGeometry类构建的,BufferGeometry是一个没有任何形状的空几何体,你可以通过BufferGeometry自定…

SinNerf理解和效果

文章目录 SinNerf 解决的问题方法和结构自己训练的效果 SinNerf 解决的问题 该方法主要解决的问题是&#xff1a; 现有都使用多张照片来进行nerf 表示的学习&#xff0c;这篇文章的话&#xff0c;主要是想使用一张单视角的照片来Nerf表示的学习。通过从单张照片中得到的伪标签…

【SpringBoot集成Spring Security】

一、前言 Spring Security 和 Apache Shiro 都是安全框架&#xff0c;为Java应用程序提供身份认证和授权。 二者区别 Spring Security&#xff1a;重量级安全框架Apache Shiro&#xff1a;轻量级安全框架 关于shiro的权限认证与授权可参考小编的另外一篇文章 &#xff1a; …

IDEA模版快速生成Java方法体

新建模版组myLive 在模版组下新建模版finit 在模版text内输入以下脚本 LOGGER.info("$className$.$methodName$>$parmas1$", $parmas2$); try {} catch (Exception e) {LOGGER.error("$className$.$methodName$>error:", e); }LOGGER.info("$c…

win10没有Hyper-v的解决方法

win10没有Hyper-v的解决方法 问题&#xff1a;最近想装下docker&#xff0c;但是在控制面板-程序-启用或关闭Windows功能下找不到Hyper-v节点。 废话不多说&#xff0c;直接上实操教程 1.将下面命令复制到文本文档中&#xff0c;并将文档重命名Hyper.cmd pushd "%~dp0&q…

实用小工具-python esmre库实现word查找

python esmre库实现word查找 前言&#xff1a; 在文本中匹配特定的字符串&#xff0c;一般可以用普通的字符串匹配算法&#xff0c;KMP算法&#xff1b; python中提供了一个库&#xff0c;esmre, 通过预先将字符串存到esm对象中&#xff0c;利用这些字符串从候选的字符串中进行…

Spring Boot实战:图书信息网站

实战概述&#xff1a;Spring Boot图书信息网站开发 项目背景 随着数字化时代的到来&#xff0c;图书信息网站为用户提供了一个便捷的在线浏览和购买图书的平台。本实战项目旨在通过Spring Boot框架开发一个图书信息网站&#xff0c;实现图书展示、用户登录和管理等功能。 项…