C++ 类与对象——超详细入门指南(上篇)

C++ 类与对象——详细入门指南

1. 类的定义

在C++中,类是面向对象编程的基础概念之一。类通过将数据和行为封装在一起,模拟现实世界中的实体。通过类,我们可以定义对象的属性(成员变量)和行为(成员函数)。

1.1 类定义的基本格式

类的定义使用 class 关键字,后面跟上类的名称。在C++中,类体需要用大括号 {} 包裹,并在类定义结束时加上分号 ;。类中的内容称为类的成员,包括:

  • 成员变量:即类的属性,存储类的状态。
  • 成员函数:即类的方法,定义类的行为。
示例代码
#include <iostream>
using namespace std;

class Stack {
public:
    // 成员函数:初始化栈
    void Init(int n = 4) {
        array = (int*)malloc(sizeof(int) * n);
        if (nullptr == array) {
            perror("malloc申请空间失败");
            return;
        }
        capacity = n;
        top = 0;
    }

    // 成员函数:将元素推入栈
    void Push(int x) {
        // 如果栈满,进行扩容
        array[top++] = x;
    }

    // 成员函数:获取栈顶元素
    int Top() {
        assert(top > 0);
        return array[top - 1];
    }

    // 成员函数:销毁栈
    void Destroy() {
        free(array);
        array = nullptr;
        top = capacity = 0;
    }

private:
    // 成员变量:栈的实现细节
    int* array;
    size_t capacity;
    size_t top;
};

int main() {
    Stack st;
    st.Init();
    st.Push(1);
    st.Push(2);
    cout << st.Top() << endl;
    st.Destroy();
    return 0;
}
解释
  • class:定义类的关键字。
  • Stack:类的名称。
  • 成员函数:例如 InitPushTopDestroy,它们定义了类的行为。
  • 成员变量:例如 arraycapacitytop,这些变量存储类的状态或属性。
  • public/private:访问限定符,决定了类的成员是如何被访问的。public 成员可以在类外访问,private 成员则只能在类内部使用。

1.2 访问限定符

访问限定符是C++实现封装的方式之一,它决定了类的成员能否被类外部的用户访问。

  • public:修饰的成员可以在类外部直接访问。
  • private:修饰的成员只能在类内部访问,类外不能直接访问。
  • protected:类似于 private,但在继承中,子类可以访问 protected 成员。之后会详细讲解
示例代码
class Date {
public:
    // 公有成员函数
    void Init(int year, int month, int day) {
        _year = year;
        _month = month;
        _day = day;
    }

private:
    // 私有成员变量
    int _year;
    int _month;
    int _day;
};

int main() {
    Date d;
    d.Init(2024, 3, 31);
    return 0;
}
解释
  • public:声明的 Init 函数是公共的,可以在类外部使用。
  • private_year_month_day 是私有成员,不能在类外部直接访问,只有类的成员函数能访问这些变量。

1.3 类域

类的作用域决定了类成员的可访问性。在类外定义成员函数时,需要通过作用域解析符 :: 指明成员属于哪个类。例如,如果在类外定义成员函数,需要使用类名和作用域解析符。

示例代码
#include <iostream>
using namespace std;

class Stack {
public:
    void Init(int n = 4);
private:
    int* array;
    size_t capacity;
    size_t top;
};

// 使用作用域解析符在类外定义成员函数
void Stack::Init(int n) {
    array = (int*)malloc(sizeof(int) * n);
    if (nullptr == array) {
        perror("malloc申请空间失败");
        return;
    }
    capacity = n;
    top = 0;
}

int main() {
    Stack st;
    st.Init();
    return 0;
}
解释
  • Stack::Init:: 作用域解析符表示 Init 函数属于 Stack 类。通过作用域解析符,编译器可以知道该函数属于哪个类,并可以在类的作用域中查找成员变量 arraycapacitytop

1.4 成员命名规范

在C++中,通常会为类的成员变量使用特定的命名约定,以避免与函数参数或局部变量混淆。这些命名约定可以提高代码的可读性和维护性。

常见的命名约定:
  1. 使用下划线 _:在成员变量的名称前加一个下划线,以区分成员变量和其他变量。
  2. 使用 m_ 前缀:成员变量以 m_ 开头,表示 “member”(成员变量)。
  3. 驼峰命名法:使用驼峰命名法,例如 myVariable,使得代码更易读。
示例:
class Date {
private:
    int _year;       // 使用下划线前缀
    int m_month;     // 使用 m_ 前缀
    int dayOfMonth;  // 使用驼峰命名法
public:
    void SetDate(int year, int month, int day) {
        _year = year;
        m_month = month;
        dayOfMonth = day;
    }
};
拓展:

这种命名约定并不是C++语言的强制要求,而是遵循公司或团队的编码风格指南。使用这些命名约定可以避免命名冲突,并让代码的意图更加明确。例如,在 SetDate 函数中,使用 _yearyear 可以轻松区分成员变量和函数参数,减少混淆。

1.5 class与struct的默认访问权限

在C++中,classstruct 的区别主要在于默认的访问权限:

  • class 中,未标明的成员变量和成员函数默认是 private
  • struct 中,未标明的成员变量和成员函数默认是 public
示例:
struct ExampleStruct {
    int a; // 默认 public
};

class ExampleClass {
    int b; // 默认 private
};

2. 类的实例化

2.1 实例化概念

实例化是指在物理内存中创建对象的过程。类是对象的抽象描述,它提供了对象的结构和行为,但是类本身并不占用物理空间,只有当类被实例化时,才会在内存中分配空间。

示例代码
#include <iostream>
using namespace std;

class Date {
public:
    void Init(int year, int month, int day) {
        _year = year;
        _month = month;
        _day = day;
    }

    void Print() {
        cout << _year << "/" << _month << "/" << _day << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};

int main() {
    Date d1;
    d1.Init(2024, 3, 31);
    d1.Print();

    Date d2;
    d2.Init(2024, 7, 5);
    d2.Print();

    return 0;
}
解释
  • Date d1:实例化一个 Date 对象 d1
  • Init:调用 Init 函数初始化 d1 对象的成员变量 _year_month_day
  • Print:输出对象的日期信息。

2.2 对象的大小

当类被实例化为对象时,对象的大小取决于类的成员变量成员变量需要分配空间,但成员函数不会在对象中存储。成员函数是存储在单独的代码段中的一段指令。

示例代码
#include <iostream>
using namespace std;

class A {
private:
    char _ch;  // 1 字节
    int _i;    // 4 字节
};

int main() {
    A a;
    cout << sizeof(a) << endl;  // 输出对象的大小
    return 0;
}
解释
  • 该类的成员变量 _ch_i 总共占用 5 字节,但由于内存对齐,实际对象的大小可能是 8 字节。内存对齐规则保证了访问效率(见下文解释)。

2.3 对象的存储

在C++中,当类被实例化为对象时,只有成员变量会被存储在对象中,而成员函数不会。成员函数是存储在代码段中的一段指令,所有对象共享同一份函数指令。因此,无论类有多少个对象,成员函数只会存在一份。

示例:
class Date {
public:
    void Init(int year, int month, int day);
private:
    int _year;
    int _month;
    int _day;
};

3. this 指针

3.1 什么是 this 指针

this 是C++中的一个隐式指针,存在于每一个非静态成员函数中。this 指针指向调用该成员函数的当前对象。在类的成员函数中,this 指针可以用来访问类的成员变量和成员函数。

  • 当我们在成员函数中使用类的成员变量时,本质上是通过 this 指针访问该成员变量。
  • this 指针是隐含的,C++自动将它传递给所有非静态成员函数。
this 指针的内部机制

在C++中,当类的成员函数被调用时,this 指针会被自动传递给该函数。this 指针的类型是 const Type* const,它是一个只读指针,指向当前对象。你不能修改 this 指针的值,但可以通过 this 访问对象的成员。

3.2 示例代码

#include<iostream>
using namespace std;

class Date {
public:
    void Init(int year, int month, int day) {
        this->_year = year;  // 通过 this 指针访问成员变量
        this->_month = month;
        this->_day = day;
    }

    void Print() {
        cout << _year << "/" << _month << "/" << _day << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};

int main() {
    Date d1;
    d1.Init(2024, 3, 31);
    d1.Print();

    return 0;
}
解释
  • this:在 Init 函数中,this->_year = year 表示将传入的参数 year 赋值给当前对象的 _year 成员变量。this 指针指向当前调用 Init 函数的对象(即 d1)。
拓展解释:this 指针在什么时候使用?

在通常的情况下,编写代码时我们不需要显式使用 this 指针,因为C++会自动处理类的成员和参数之间的冲突。但是在某些情况下,例如当函数的参数名称和成员变量名称相同时,使用 this 指针可以明确地表示成员变量。

void Init(int year, int month, int day) {
    this->_year = year;  // 通过 this 指针区分成员变量和函数参数
    this->_month = month;
    this->_day = day;
}

在上面的代码中,如果不使用 this,编译器会把 year 解释为函数参数,而不是成员变量 _year

好的,我会在 this 指针部分补充所有的测试内容,并在该部分加入关于 命名 的内容,确保详细且连贯。以下是需要补充的内容:


3.3 this指针的测试题

测试题 1:this 指针的基本行为

#include<iostream>
using namespace std;

class A {
public:
    void Print() {
        cout << "A::Print()" << endl;
    }
private:
    int _a;
};

int main() {
    A* p = nullptr;
    p->Print();  // 能否正常运行?
    return 0;
}
问题描述:

我们定义了一个 A 类,包含一个成员函数 Print(),它只是输出一条字符串。我们通过空指针 p 调用 Print() 函数,询问这段代码能否正常运行。

解析:
  1. main() 函数中,A* p = nullptr; 创建了一个指向 A 类的空指针 p
  2. 随后我们通过空指针 p->Print() 来调用成员函数 Print(),这里的 this 指针其实是空指针。

为什么不会报错?

  • 当我们调用 p->Print() 时,this 指针实际上等于 nullptr,但由于 Print() 函数没有访问任何成员变量,因此C++允许这个调用。
  • this 指针是隐含的,虽然在函数内部会传递 this,但是如果成员函数不访问任何成员变量,C++不需要解引用这个空指针,因此不会出现空指针访问的错误。
  • Print() 函数只是输出了一段固定的文本,不涉及对象的状态或成员变量,因此即使 this 是空指针,也不会导致问题。
正确答案:C. 正常运行

测试题 2:this 指针与成员变量的访问

#include<iostream>
using namespace std;

class A {
public:
    void Print() {
        cout << "A::Print()" << endl;
        cout << _a << endl;
    }
private:
    int _a;
};

int main() {
    A* p = nullptr;
    p->Print();  // 能否正常运行?
    return 0;
}
问题描述:

这段代码和前一个问题类似,但在 Print() 函数中多了一个成员变量 _a 的访问。通过空指针 p 调用 Print(),是否会出现空指针访问的问题?

解析:
  1. main() 中,和之前一样,A* p = nullptr; 创建了一个指向 A 类的空指针 p
  2. 当调用 p->Print() 时,this 指针仍然是 nullptr

为什么会崩溃?

  • Print() 函数中,除了输出 A::Print() 以外,代码还试图访问类的成员变量 _a
  • this 指针为 nullptr 时,访问 this->_a 等同于尝试通过空指针访问成员变量。这是一种未定义行为,在大多数系统中会导致程序崩溃。
  • 成员变量 _a 存储在对象的内存空间中,而通过空指针访问成员变量时,由于没有实际的对象空间可用,因此程序在运行时会发生崩溃。
正确答案:B. 运行时崩溃

详细解释:为什么不是空指针访问

在这两个测试题中,关键点在于是否访问了成员变量

  1. 测试题 1 中,Print() 函数没有访问成员变量,所以即使 this 是空指针,C++也不会触发空指针访问错误。这是因为成员函数本质上只是一个在内存中的函数指针,调用它并不一定需要访问实际对象的内存。

  2. 测试题 2 中,Print() 函数试图访问成员变量 _a。由于成员变量存储在对象的内存空间中,而空指针 this 并没有指向有效的内存区域,所以在运行时会试图通过空指针访问内存,导致程序崩溃。这是典型的空指针访问错误。

总结来说,空指针调用成员函数本身并不会报错,只要该成员函数不涉及访问成员变量或其他依赖对象内存的操作。然而,一旦成员函数试图通过 this 指针访问成员变量,程序就可能会崩溃,因为 thisnullptr,没有有效的内存空间可供访问。


测试题 3:this 指针的存储位置

选择题:this 指针存在于内存的哪个区域?

  • A. 栈
  • B. 堆
  • C. 静态区
  • D. 常量区
  • E. 对象里

正确答案:A. 栈

解释
this 指针作为成员函数的一个隐含参数,存储在栈中。每当一个成员函数被调用时,this 指针会作为函数参数被压入栈中。


4. C++和C语言实现Stack的对比

通过C和C++语言实现 Stack 栈的对比,展现了C++相较于C语言在封装和安全性方面的优势。

4.1 C语言实现Stack

在C语言中,实现 Stack 需要使用 struct 来定义栈的数据结构,并且所有的栈操作(如初始化、压栈、弹栈等)都通过独立的函数实现。由于C语言不支持面向对象编程,数据和操作必须分开处理,所有栈操作的函数需要手动传递 Stack 结构体的指针作为参数。

C语言实现Stack的代码示例
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef int STDataType;
typedef struct Stack {
    STDataType* array;
    int top;
    int capacity;
} Stack;

void Init(Stack* s) {
    s->array = (STDataType*)malloc(4 * sizeof(STDataType));
    s->capacity = 4;
    s->top = 0;
}

void Destroy(Stack* s) {
    free(s->array);
    s->array = NULL;
    s->top = 0;
    s->capacity = 0;
}

void Push(Stack* s, STDataType x) {
    if (s->top == s->capacity) {
        s->capacity *= 2;
        s->array = (STDataType*)realloc(s->array, s->capacity * sizeof(STDataType));
    }
    s->array[s->top++] = x;
}

STDataType Top(Stack* s) {
    assert(s->top > 0);
    return s->array[s->top - 1];
}

void Pop(Stack* s) {
    assert(s->top > 0);
    --s->top;
}

bool Empty(Stack* s) {
    return s->top == 0;
}

int main() {
    Stack s;
    Init(&s);
    Push(&s, 1);
    Push(&s, 2);
    printf("栈顶元素: %d\n", Top(&s));
    Pop(&s);
    printf("栈顶元素: %d\n", Top(&s));
    Destroy(&s);
    return 0;
}
C语言实现Stack的详细解释
  • 结构体Stack:这是一个结构体,包含了三个成员:

    • array:一个指向栈的动态数组的指针,用来存储栈中的元素。
    • top:指向栈顶元素的指针,它代表当前栈中元素的个数。
    • capacity:栈的容量,表示栈中最多可以容纳的元素个数。
  • 函数Init:用于初始化栈的大小,并为数组分配内存。C语言中没有构造函数,因此必须通过函数显式初始化结构体。

  • 函数Push:将元素压入栈中,如果栈满则进行扩容操作,使用 realloc 函数为栈分配更大的内存。

  • 函数Top:返回栈顶元素,调用时需要确保栈不为空。

  • 函数Pop:将栈顶元素弹出,减少 top 的值。

  • 内存管理:通过 mallocrealloc 动态分配内存,使用 free 释放内存。


4.2 C++语言实现Stack

C++通过类的封装,可以将数据和操作放在一起。栈的实现不仅更为简洁,而且通过封装性提高了代码的安全性和可维护性。相比C语言,C++不需要手动传递 Stack 指针,而是通过类的成员函数自动操作栈。

C++实现Stack的代码示例
#include<iostream>
using namespace std;

class Stack {
public:
    Stack(int n = 4) {
        _array = (int*)malloc(sizeof(int) * n);
        _capacity = n;
        _top = 0;
    }

    ~Stack() {
        free(_array);
        _array = nullptr;
    }

    void Push(int x) {
        if (_top == _capacity) {
            _capacity *= 2;
            _array = (int*)realloc(_array, _capacity * sizeof(int));
        }
        _array[_top++] = x;
    }

    int Top() {
        assert(_top > 0);
        return _array[_top - 1];
    }

    void Pop() {
        assert(_top > 0);
        --_top;
    }

    bool Empty() {
        return _top == 0;
    }

private:
    int* _array;
    size_t _capacity;
    size_t _top;
};

int main() {
    Stack s;
    s.Push(1);
    s.Push(2);
    cout << "栈顶元素: " << s.Top() << endl;
    s.Pop();
    cout << "栈顶元素: " << s.Top() << endl;
    return 0;
}
C++实现Stack的详细解释
  • 构造函数和析构函数

    • 构造函数 Stack(int n = 4):用于初始化栈,分配内存并设置栈的容量。这里的 n 是栈的初始大小,默认值为4。构造函数在对象创建时自动调用,确保对象处于有效的状态。
    • 析构函数 ~Stack():当栈对象被销毁时,自动释放动态分配的内存。这是C++相比C语言的一个显著优势,因为不需要手动调用 Destroy 函数来释放资源。
  • 成员函数Push:与C语言中的 Push 函数类似,用于将元素压入栈中。栈满时会自动扩容,但通过成员函数的封装,这一操作对类外的用户是透明的,用户只需要调用 Push 方法即可。

  • 成员函数Top:返回栈顶元素,和C语言一样,操作之前会检查栈是否为空,保证操作的安全性。

  • 封装性:相比C语言,C++通过类的 private 成员变量 _array_capacity_top,将栈的实现细节封装起来,防止用户直接操作这些数据。所有的操作都通过 public 成员函数完成,保证了数据的安全性。

拓展解释:构造函数和析构函数(在之后会详细解释
  • 构造函数:它是类中的特殊函数,当类的对象被创建时,构造函数会被自动调用,用于初始化对象。在 Stack 类中,构造函数初始化栈的容量,并为数组分配内存。

  • 析构函数:它也是类中的特殊函数,当对象生命周期结束(如对象作用域结束时)时,析构函数会自动调用,用于释放对象所占用的资源。在 Stack 类中,析构函数用于释放 malloc 分配的内存,避免内存泄漏。


4.3 C++和C语言实现Stack的对比总结

通过对C和C++实现 Stack 的对比,可以得出以下几点总结:

  • 封装性:C++通过类的封装将数据和操作整合在一起,类的用户不需要关心栈的实现细节,而C语言的实现则需要用户手动调用函数并管理结构体的状态。

  • 内存管理:C语言中,内存管理是手动的,开发者必须显式调用 free 函数释放内存。而在C++中,析构函数自动负责资源的释放,避免了忘记释放内存导致的内存泄漏问题。

  • 安全性:C++中的类通过 private 关键字保护类的内部数据,防止外部代码随意修改类的成员变量,增强了数据的安全性。而C语言没有这种封装机制,所有数据都可以通过结构体直接访问,容易导致意外的修改和错误。


5. 内存对齐

内存对齐是计算机系统中用于优化数据访问的机制。在C++中,类的成员变量在内存中的存放位置要遵循特定的对齐规则,以提高CPU的访问效率。

这部分内容在C语言结构体详细介绍过,详情请见

5.1 内存对齐规则

内存对齐规则规定:

  1. 第一个成员存储在偏移量为0的地址处。

  2. 其他成员必须存储在某个对齐数的整数倍的地址处。

  3. 对齐数取决于编译器的设置和变量的类型,通常为4字节或8字节。

5.2 示例代码

#include<iostream>
using namespace std;

class A {
private:
    char _ch;  // 1 字节
    int _i;    // 4 字节
};

int main() {
    A a;
    cout << "对象 A 的大小: " << sizeof(a) << " 字节" << endl;  // 输出对象大小
    return 0;
}
解释

尽管 A 类中的 _ch_i 变量加起来只有 5 字节,但由于内存对齐规则,类的实际大小为 8 字节。这是因为 int 变量 _i 要求4字节对齐,而 char 只占1字节,因此在 char 后面会插入3个字节的填充空间,以便 int 对齐到4字节边界。

拓展解释:为什么需要内存对齐?
  • 内存对齐的意义:内存对齐的目的是为了优化CPU的读取速度。在现代计算机架构中,处理器一次性读取的内存块大小通常为4字节或8字节。如果数据存储在不对齐的地址上,处理器需要执行更多的操作来读取数据,从而影响性能。因此,通过对齐存储,处理器可以更快速地读取和写入数据。

  • 内存对齐和空间浪费:虽然内存对齐提高了数据访问的效率,但也可能会造成空间浪费。例如,在上例中,char 类型只需要1字节,但为了对齐 int,额外浪费了3个字节的填充空间。这种权衡在性能优化和内存空间利用之间找到了平衡。


5.3 内存对齐的影响

内存对齐会影响类的实际大小。例如,以下代码展示了不同对齐方式下对象的大小变化:

#include<iostream>
#pragma pack(1)  // 设置内存对齐为1字节
using namespace std;

class B {
public:
    char _ch;  // 1字节
    int _i;    // 4字节
};

int main() {
    B b;
    cout << "对象 B 的大小: " << sizeof(b) << " 字节" << endl;  // 输出对象 B 的大小为 5 字节
    return 0;
}
#pragma pack()  // 恢复默认对齐
解释

通过使用 #pragma pack(1) 指令,我们将类 B 的内存对齐设置为 1 字节对齐。这样,char 类型占用 1 字节,int 类型占用 4 字节,总共5字节,没有插入额外的填充字节。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

今日指数-day08实战完整代码

今日指数-day08 1. 个股最新分时行情数据 1.1 个股最新分时行情功能说明 1&#xff09;个股最新分时行情功能原型 2&#xff09;个股最新分时行情数据接口分析 功能描述&#xff1a;获取个股最新分时行情数据&#xff0c;主要包含&#xff1a;开盘价、前收盘价、最新价、最…

AI周报(9.29-10.5)

AI应用-Elayne公司临终规划和自动化遗产结算 创业公司Elayne成立于2023年&#xff0c;由Adria Ferrier和Jake Grafenstein共同创立&#xff0c;Adria Ferrier担任CEO&#xff0c;总部位于科罗拉多州丹佛市。 Elayne公司专注于遗产规划和结算领域&#xff0c;通过人工智能技术…

【Diffusion分割】CTS:基于一致性的医学图像分割模型

CTS: A Consistency-Based Medical Image Segmentation Model 摘要&#xff1a; 在医学图像分割任务中&#xff0c;扩散模型已显示出巨大的潜力。然而&#xff0c;主流的扩散模型存在采样次数多、预测结果慢等缺点。最近&#xff0c;作为独立生成网络的一致性模型解决了这一问…

【C++】STL——list的模拟实现

目录 前言list介绍list的模拟实现总体结构节点类迭代器类链表类 默认成员函数构造函数拷贝构造赋值重载析构函数 迭代器实现双向迭代器迭代器的其他功能用多参数模板完成最终的迭代器类 list的容量相关和数据访问empty()和size()front()和back() list的修改操作任意位置插入和删…

数据结构 ——— C语言实现无哨兵位单向不循环链表

目录 前言 动态顺序表的缺陷 单链表的概念 单链表中节点的结构 单链表逻辑结构示意图​编辑 实现单链表前的准备工作 实现单链表 1. 定义节点的指针 2. 创建节点 3. 打印单链表中的所有数据 4. 在单链表头部插入数据 5. 在单链表尾部插入数据 6. 在单链表头部删除数…

脏读、不可重复读、幻读的解决方法

上一篇博客提到了脏读、不可重复读、幻读的含义&#xff0c;也知道了是因为什么情况导致出现的这些问题&#xff0c;这篇博客就带大家一起来了解一下他们的解决办法~ 脏读&#xff1a;脏读出现的原因主要是因为一个事务读取了另外一个事务未提交的数据&#xff0c;就可能出现脏…

掌握嵌套子查询:复杂 SQL 中 * 列的准确表列关系

在日常开发中&#xff0c;我们常常需要对复杂的 SQL 进行数据血缘分析。 本文重点讨论在具有 * 列的嵌套子查询中建立表和列之间正确关系的挑战。使用 Teradata SQL 代码示例来说明该过程。 本文聚焦于一个别名为 SUBSCRIBER_ 的子查询及其派生的列&#xff0c;这些列在外层查…

无需VPN!大厂力作:免费AI对口型神器登场,让你的视频制作更简单!

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 &#xff08;偶尔会因为推荐工具&#xff…

《深度学习》OpenCV 图像拼接 原理、参数解析、案例实现

目录 一、图像拼接 1、直接看案例 图1与图2展示&#xff1a; 合并完结果&#xff1a; 2、什么是图像拼接 3、图像拼接步骤 1&#xff09;加载图像 2&#xff09;特征点检测与描述 3&#xff09;特征点匹配 4&#xff09;图像配准 5&#xff09;图像变换和拼接 6&am…

实验3 选择结构

1、计算分段函数的值 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <math.h> int main() {double x,y0;scanf("%lf",&x);if(x<0){printf("error!\n");return 0;}if(0<x&&x<1){ylog10(x);}else if(1<…

缓存数据减轻服务器压力

问题:不是所有的数据都需要请求后端的 不是所有的数据都需要请求后端的,有些数据是重复的、可以复用的解决方案:缓存 实现思路:每一个分类为一个key,一个可以下面可以有很多菜品 前端是按照分类查询的,所以我们需要通过分类来缓存缓存代码 /*** 根据分类id查询菜品** @pa…

Java | Leetcode Java题解之第459题重复的子字符串

题目&#xff1a; 题解&#xff1a; class Solution {public boolean repeatedSubstringPattern(String s) {return kmp(s s, s);}public boolean kmp(String query, String pattern) {int n query.length();int m pattern.length();int[] fail new int[m];Arrays.fill(fa…

54.二叉树的最大深度

迭代 class Solution {public int maxDepth(TreeNode root) {if(rootnull){return 0;}int de0;Queue<TreeNode> qunew LinkedList<>();TreeNode tn;int le;qu.offer(root);while(!qu.isEmpty()){lequ.size();while(le>0){tnqu.poll();if(tn.left!null){qu.offe…

学会这几个简单的bat代码,轻松在朋友面前装一波13[通俗易懂]

大家好&#xff0c;又见面了&#xff0c;我是你们的朋友全栈君。 这个标题是干什么用的? 最近看晚上某些人耍cmd耍的十分开心&#xff0c;还自称为“黑客”&#xff0c;着实比较搞笑.他们那些花里胡哨的东西在外行看来十分nb,但只要略懂一些&#xff0c;就会发现他们的那些十…

论文阅读笔记-A Comparative Study on Transformer vs RNN in Speech Applications

前言 介绍 序列到序列模型已广泛用于端到端语音处理中,例如自动语音识别(ASR),语音翻译(ST)和文本到语音(TTS)。本文着重介绍把Transformer应用在语音领域上并与RNN进行对比。与传统的基于RNN的模型相比,将Transformer应用于语音的主要困难之一是,它需要更复杂的配…

JavaScript 数组方法

数组(array)是按次序排列的一组值。每个值的位置都有编号(从0开始)&#xff0c;整个数组用方括号表示。两端的方括号是数组的标志。 var a["a","b","c"]; 除了在定义时赋值&#xff0c;数组也可以先定义后赋值。 var arr[];arr[1]"a"…

Qt_绘图

目录 1、绘图核心类 2、QPainter类的使用 2.1 绘制线段 2.2 绘制矩形 2.3 绘制圆形 2.4 绘制文本 3、QPen类的使用 3.1 使用画笔 4、QBrush类的使用 4.1 使用画刷 5、绘制图片 5.1 测试QPixmap 5.1.1 图片移动 5.1.2 图标缩小 5.1.3 旋转图片 5.1.4 将…

windows10或11家庭版实现远程桌面连接控制

远程协助是一种Windows工具&#xff0c;允许控制者使用鼠标和键盘远程控制接受者的计算机&#xff0c;从某种程度上讲&#xff0c;这也是Win10家庭版无法远程桌面的一个有效替代方案。 步骤1. 在使用Windows远程协助之前&#xff0c;您需要先更改某些设置&#xff0c;右键单击…

封装el-upload组件,用于上传图片和视频

使用环境 vue3element-ui plus 需要根据后端返回结构修改的函数&#xff1a;onPreview onRemove onSuccess 组件使用 基本使用 源代码&#xff1a; <script setup> import AutoUploadFile from /components/auto-upload-file/index.vue function change(urls){console.…

金智维KRPA之Excel自动化

Excel自动化操作概述 Excel自动化主要用于帮助各种类型的企业用户实现Excel数据处理自动化&#xff0c;Excel自动化是可以从单元格、列、行或范围中读取数据&#xff0c;向其他电子表格或工作簿写入数据等活动。 通过相关命令&#xff0c;还可以对数据进行排序、进行格式…