第三节-类与对象(2)默认成员函数详解

news2024/11/28 2:52:59

1.类的6个默认成员函数

如果一个类中什么成员都没有,简称为空类(空类大小为1)

空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。

默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

class Date {};

 


2. 构造函数


构造函数是用于初始化对象的特殊成员函数。虽然名称为“构造”但它的主要任务是初始化对象的成员变量,而不是为对象分配内存。构造函数的使用对于确保对象在创建时处于有效状态至关重要。

2.1 函数名与类名相同


构造函数的名字必须与类名相同。这是C++的语法要求

解释:构造函数的名字与类名相同,使得编译器能够识别它是用于初始化对象的函数,而不是普通的成员函数。
示例:
class MyClass {
public:
    MyClass() { /* 构造函数体 */ }
}

 2.2 无返回值


构造函数没有返回值,甚至不能声明void。这是C++语言规定的,构造函数的唯一目的是初始化对象,因此不需要返回任何值。

解释:构造函数的任务是初始化对象,而不是返回数据。返回值的存在会违背构造函数的设计目的。
示例:

class MyClass {
public:
    MyClass() { /* 构造函数体,无返回值 */ }
};

2.3 对象实例化时系统会自动调用


构造函数在对象实例化时自动调用。开发者不需要显式调用构造函数,编译器会在对象创建时自动执行它。

解释:构造函数的自动调用确保了对象在创建时立即处于有效状态。无论对象是作为局部变量、全局变量还是动态分配的变量,构造函数都会在创建时运行。

示例:
MyClass obj; // 调用构造函数

2.4 构造函数可以重载


构造函数可以重载,即同一个类中可以有多个构造函数,它们的参数列表必须不同。这允许对象在创建时根据不同的需求进行不同的初始化。

解释:通过构造函数的重载,可以灵活地初始化对象。例如,一个类可以有无参构造函数和带参构造函数,以满足不同的初始化需求。
示例:
class MyClass {
public:
    MyClass() { /* 无参构造函数 */ }
    MyClass(int x) { /* 带参构造函数 */ }
};


2.5 默认构造函数的生成规则


如果类中没有显式定义构造函数,编译器会自动生成一个无参的默认构造函数。但一旦用户定义了任何构造函数,编译器就不再生成默认构造函数。

解释:默认构造函数提供了一个基本的初始化方式。如果用户定义了其他形式的构造函数(如带参数的),编译器认为用户不再需要默认构造函数,因此不会自动生成


示例:
class MyClass {
    // 没有显式定义构造函数,编译器会生成默认的无参构造函数
};
MyClass obj; // 调用默认构造函数


2.6 无参构造函数与全缺省构造函数的关系


无参构造函数、全缺省构造函数、默认生成的构造函数不能同时存在。如果定义了无参构造函数或全缺省构造函数,编译器将不会再生成默认构造函数。

解释:这三种构造函数提供了相似的功能,即初始化对象而不需要显式提供参数。为了避免冲突,它们只能存在其中之一。


示例:
class MyClass {
public:
    MyClass() { /* 无参构造函数 */ }
    // MyClass(int x = 0) { /* 全缺省构造函数,不能与无参构造函数同时存在 */ }
};


注意:无参构造函数、全缺省构造函数、编译器自动默认生成的构造函数全都叫默认构造函数!!!总结来说,可以不传参的就是默认构造函数,这三个不能同时存在,但是默认构造函数可以和带参的构造函数同时存在(即上文所说的函数重载),例如半缺省、没有缺省值等的普通构造函数。

#include <iostream>
using namespace std;

class MyClass {
public:
    // 全缺省构造函数,即默认构造函数
    MyClass(int x = 10, int y = 20) {
        cout << "Called MyClass(int x = 10, int y = 20)" << endl;
        cout << "x = " << x << ", y = " << y << endl;
    }

    // 普通带参构造函数(没有缺省值)
    MyClass(double z) {
        cout << "Called MyClass(double z)" << endl;
        cout << "z = " << z << endl;
    }
};
int main() {
    MyClass obj1;           // 调用全缺省构造函数
    MyClass obj2(100);      // 调用全缺省构造函数,因为100是int类型
    MyClass obj3(3.14);     // 调用普通的带参构造函数
    return 0;
}

 2.7 内置类型与自定义类型成员变量的初始化


如果是编译器自动生成的默认构造函数对内置类型成员变量的初始化没有要求,其值不确定。对于自定义类型的成员变量,编译器会调用它们的默认构造函数进行初始化。

解释:内置类型(如int、char)的成员变量如果没有显式初始化,其值可能是未定义的。自定义类型的成员变量则必须通过其默认构造函数初始化。

示例:(这里是初始化列表,在这个系列的之后博客会讲到)
class MyClass {
public:
    MyClass() : _value(0) { /* 初始化内置类型成员变量 */ }
private:
    int _value;
    std::string _name;// 自动调用std::string的默认构造函数
}:
示例代码梳理
以下是展示上述特点的详细代码示例:

这里只是为了方便写的示例哈,如前文所述,无参和全缺省的默认构造函数只能存在一种

#include<iostream>
using namespace std;

class Date {
public:
    // 1. 无参构造函数
    Date() {
        _year = 1;
        _month = 1;
        _day = 1;
    }

    // 2. 带参构造函数
    Date(int year, int month, int day) {
        _year = year;
        _month = month;
        _day = day;
    }

    // 3. 全缺省构造函数
    Date(int year = 1, int month = 1, int day = 1) {
        _year = year;
        _month = month;
        _day = day;
    }

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

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

int main() {
    // 调用无参构造函数
    Date d1;

    // 调用带参构造函数
    Date d2(2025, 1, 1);

    // 调用全缺省构造函数
    Date d3;

    d1.Print();
    d2.Print();

    return 0;
}


通过这个详细的解析和示例代码,我们可以清晰地理解C++类的默认成员函数和构造函数的特点及其作用。这样,开发者可以根据具体需求灵活地使用和自定义这些函数,以便更好地控制对象的生命周期和资源管理。

3. 析构函数


析构函数是与构造函数功能相反的一个函数,它用于在对象生命周期结束时释放资源。C++中规定,析构函数会在对象销毁时自动调用,以完成对象中资源的清理工作。这一特性使得C++能够有效地管理内存和其他资源,防止资源泄漏。

3.1 析构函数名


析构函数的名称是类名的前面加上一个“~”符号,这是C++语法中的规定。它用于明确表示该函数是析构函数。

解释:析构函数的名字与类名相同,但在前面加上“~”符号,这使得编译器能够识别这是一个析构函数.

示例:
class MyClass {
public:
    ~MyClass() {
        // 析构函数体
    }
};


3.2无参数无返回值


析构函数不接受任何参数,也没有返回值。它的唯一任务是清理对象的资源。

解释:由于析构函数是系统自动调用的,因此它不能有参数,也不需要返回任何值.

示例:
class MyClass {
public:
    ~MyClass() {
        // 无参数,无返回值
    }
};


3.3一个类只能有一个析构函数


每个类只能定义一个析构函数。如果类中没有显式定义析构函数,系统会自动生成一个默认的析构函数。

解释:C++规定,一个类只能有一个析构函数,因为一个对象只能在生命周期结束时被销毁一次。

示例:
class MyClass {
public:
    ~MyClass() {
        // 只能有一个析构函数
    }
};


3.4 自动调用析构函数


当一个对象的生命周期结束(如对象超出作用域或显式删除对象)时,系统会自动调用析构函数来清理资源。

解释:析构函数的自动调用确保了对象在被销毁时可以正确地释放资源,防止资源泄漏。

示例:
class MyClass {
public:
    ~MyClass() {
        cout << "Object is being destroyed" << endl;
    }
};

int main() {
    MyClass obj; // 当obj超出作用域时,系统会自动调用析构函数
    return 0;
}


3.5 析构函数对内置类型成员


如果类中没有显式定义析构函数,编译器会自动生成一个默认析构函数。这个默认析构函数对内置类型的成员变量不做任何处理。

解释:对于内置类型(如int、char等),默认析构函数不需要释放资源。但对于自定义类型的成员,编译器生成的析构函数会调用这些成员的析构函数。

示例:
class MyClass {
private:
    int _value;
public:
    // 编译器自动生成的析构函数对内置类型不做处理
};


3.6 显式写析构函数情况


如果显式定义了析构函数,对于自定义类型的成员变量,它们的析构函数也会被自动调用。

解释:当显式定义析构函数时,C++确保所有自定义类型的成员都会在对象销毁时调用其析构函数,正确地释放资源。

示例:
class MyClass {
private:
    std::string _name; // 自定义类型成员
public:
    ~MyClass() {
        // 自定义类型的成员变量会自动调用其析构函数
    }
};


3.7 析构函数可以不写的情况


如果类中没有动态分配的资源或其他需要手动释放的资源,可以不显式定义析构函数,使用编译器生成的默认析构函数。

解释:对于没有动态资源的类,编译器生成的析构函数已经足够使用,不需要额外的析构逻辑。

示例:
class MyClass {
private:
    int _value; // 没有动态资源,编译器生成的析构函数已足够
};


3.8局部析构顺序


在一个局部作用域内定义的多个对象,C++规定后定义的对象会先调用析构函数。

解释:这一规则确保了对象按照“后进先出”的顺序销毁,符合栈的逻辑。

示例:
class MyClass {
public:
    ~MyClass() {
        cout << "Destructor called" << endl;
    }
};

int main() {
    MyClass obj1;
    MyClass obj2;
    // obj2会在obj1之前被销毁
    return 0;
}


示例代码梳理
以下是完整展示上述析构函数特点的详细代码示例:

#include<iostream>
using namespace std;

typedef int STDataType;

class Stack {
public:
    Stack(int n = 4) {
        _a = (STDataType*)malloc(sizeof(STDataType) * n);
        if (_a == nullptr) {
            perror("malloc申请空间失败");
            return;
        }
        _capacity = n;
        _top = 0;
    }

    ~Stack() { // 自定义析构函数,释放动态分配的内存
        cout << "~Stack()" << endl;
        free(_a);
        _a = nullptr;
        _top = _capacity = 0;
    }

private:
    STDataType* _a;
    size_t _capacity;
    size_t _top;
};

// 两个Stack实现队列
class MyQueue {
public:
    MyQueue() : pushst(), popst() {}

    // 默认析构函数自动调用两个Stack成员的析构函数
    // 显式定义的析构函数,也会自动调用Stack成员的析构函数
    /*~MyQueue() {}*/

private:
    Stack pushst;
    Stack popst;
};

int main() {
    Stack st;

    MyQueue mq; // MyQueue的析构函数会自动调用pushst和popst的析构函数

    return 0;
}

4. 拷贝构造函数


拷贝构造函数是一种特殊的构造函数,它用于通过已有对象来创建一个新的对象。在C++中,如果构造函数的第一个参数是自身类类型的引用,并且任何额外的参数都有默认值,那么这个构造函数就是拷贝构造函数。

4.1拷贝构造函数是构造函数的一个重载


拷贝构造函数实际上是构造函数的一种重载形式,它与普通构造函数的区别在于其参数类型和目的。解释:拷贝构造函数的定义方式与普通构造函数类似,但它的第一个参数必须是同类对象的引用,用于创建新对象时进行对象的复制。

示例:
class MyClass {
public:
    MyClass(int value) {
_value = value;
} { }  // 普通构造函数

    MyClass(const MyClass& other) {        // 拷贝构造函数
        _value = other._value;
    }

private:
    int _value;
};


4.2拷贝构造函数的第一个参数必须是类类型对象的引用


拷贝构造函数的第一个参数必须是类类型的引用,不能是传值,因为传值会导致编译器不断调用拷贝构造函数,最终引发无限递归,导致编译错误。解释:通过引用传递对象可以避免不必要的拷贝操作,并且能够直接访问原对象的内容。这种设计是为了防止调用拷贝构造函数时再次触发拷贝,从而引发无限递归。

示例:
class MyClass {
public:
    MyClass(const MyClass& other) {  // 正确:使用引用作为参数
        _value = other._value;
    }

    // MyClass(MyClass other) {       // 错误:传值会导致无限递归
    //     _value = other._value;
    // }

private:
    int _value;
};


4.3. 调用拷贝构造函数


在C++中,当自定义类型对象需要被拷贝时(如传值传参或返回对象时),系统会自动调用拷贝构造函数。这是C++管理对象生命周期的一个基本机制。

解释:无论是通过值传递一个对象,还是从函数中返回一个对象,C++都会调用拷贝构造函数来创建新的对象副本。这确保了对象能够被正确地拷贝和初始化。

示例:
void Func(MyClass obj) {
    // 传值调用,自动调用拷贝构造函数
}

MyClass ReturnObject() {
    MyClass temp(10);
    return temp;  // 返回对象时,自动调用拷贝构造函数
}

int main() {
    MyClass obj1(10);
    MyClass obj2 = obj1;  // 调用拷贝构造函数
    Func(obj1);           // 调用拷贝构造函数
    MyClass obj3 = ReturnObject();  // 调用拷贝构造函数
    return 0;
}


4.4. 编译器会自动生成拷贝构造函数


如果类中没有显式定义拷贝构造函数,编译器会自动生成一个默认的拷贝构造函数。这个默认的拷贝构造函数会对内置类型成员变量进行浅拷贝,对自定义类型成员变量调用它们的拷贝构造函数。

解释:编译器生成的默认拷贝构造函数能够满足大部分情况下的需求,尤其是对于没有指针成员或动态资源的类。然而,对于涉及动态分配的资源,浅拷贝不合适,需要自定义拷贝构造函数来实现深拷贝。(如下会讲)

示例:
class SimpleClass {
public:
    int _value;

    // 未显式定义拷贝构造函数,编译器会生成默认的拷贝构造函数
};

int main() {
    SimpleClass obj1;
    obj1._value = 42;
    SimpleClass obj2 = obj1;  // 自动生成的拷贝构造函数
    return 0;
}


4.5. 编译器自动生成的拷贝构造函数


如果类成员全部是内置类型(如int、char),编译器自动生成的拷贝构造函数可以完成所需的拷贝,无需显式定义。然而,如果类成员包含指针或动态资源,编译器生成的浅拷贝可能不合适,需要自定义实现深拷贝。

解释:浅拷贝只会复制指针的地址,而不会复制指针所指向的数据。这在动态内存管理中可能导致多个对象共享同一块内存,从而引发资源释放时的冲突。因此,对于涉及动态内存的类,通常需要自定义深拷贝构造函数。
 

示例:
class Stack {
public:
    Stack(int size) {
        _data = new int[size];
        _size = size;
    }

    // 自定义拷贝构造函数,实现深拷贝
    Stack(const Stack& other) {
        _data = new int[other._size];//之后在内存管理会讲到
        _size = other._size;
        for (int i = 0; i < _size; ++i) {
            _data[i] = other._data[i];
        }
    }

    ~Stack() {
        delete[] _data;  // 析构函数释放资源
    }

private:
    int* _data;
    int _size;
};


4.6 拷贝构造函数在传值返回时的行为


当通过传值返回一个对象时,会产生一个临时对象,系统会调用拷贝构造函数来完成对象的复制。然而,传引用返回不会调用拷贝构造函数,而是返回对象的引用。

解释:在C++中,通过值返回对象时,编译器会调用拷贝构造函数来创建返回值的副本。如果通过引用返回对象,则没有拷贝发生。然而,引用返回需要确保返回的对象在函数结束后仍然存在,否则会导致悬空引用。
 

示例:
MyClass ReturnByValue() {
    MyClass temp(10);
    return temp;  // 调用拷贝构造函数,返回对象副本
}

MyClass& ReturnByReference() {
    static MyClass temp(10);  // 使用static,确保返回的引用有效
    return temp;  // 返回引用,不调用拷贝构造函数
}

int main() {
    MyClass obj1 = ReturnByValue();    // 调用拷贝构造函数
    MyClass& obj2 = ReturnByReference();  // 不调用拷贝构造函数
    return 0;
}
示例代码梳理
以下是展示上述拷贝构造函数特点的详细代码示例:

#include<iostream>
using namespace std;

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

    // 自定义拷贝构造函数
    Date(const Date& d) {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }

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

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

void Func1(Date d) {
    d.Print();
}

Date Func2() {
    Date tmp(2024, 7, 5);
    return tmp;  // 返回值传递,调用拷贝构造函数
}

int main() {
    Date d1(2024, 7, 5);

    Func1(d1);  // 传值传参,调用拷贝构造函数

    Date d2(d1);  // 显式调用拷贝构造函数
    d2.Print();

    Date d3 = d1;  // 另一种形式的拷贝构造
    d3.Print();

    Date ret = Func2();  // 调用拷贝构造函数
    ret.Print();

    return 0;
}


通过这些代码示例和解释,我们可以深入理解C++中拷贝构造函数的特性及其应用场景。这些知识点对编写高效、安全的C++代码至关重要,特别是在处理自定义类型和动态资源时,掌握拷贝构造函数的用法可以有效防止潜在的错误和资源泄漏。

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

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

相关文章

DOM树(下) -- 第八课

文章目录 前言一、DOM属性操作1. 获取属性值2. 设置属性值3. 移除属性值 二、节点1.什么是节点?2. 节点层级1. 获取父级节点2. 获取兄弟节点3. 获取子节点 3. 节点操作1. 创建节点2. 添加和删除节点 三、事件进阶1. 注册事件1. 传统方式2. 监听方式 2. 删除事件3. 事件流 四、…

第4篇:MSSQL日志分析----应急响应之日志分析篇

常见的数据库攻击包括弱口令、SQL注入、提升权限、窃取备份等。对数据库日志进行分析&#xff0c;可以发现攻击行为&#xff0c;进一步还原攻击场景及追溯攻击源。 0x01 MSSQL日志分析 首先&#xff0c;MSSQL数据库应启用日志记录功能&#xff0c;默认配置仅限失败的登录&…

Veritus netbackup 管理控制台无法连接:未知错误

节假日停电&#xff0c;netbackup服务器意外停机后重新开机&#xff0c;使用netbackup管理控制台无法连接&#xff0c;提示未知错误。 ssh连接到服务器&#xff0c;操作系统正常&#xff0c;那应该是应用有问题&#xff0c;先试一下重启服务器看看。重新正常关机&#xff0c;重…

【Ubuntu】使用阿里云apt源来更新apt源

1.前言 我在京东云买了一个云服务器&#xff0c;但是我第一次使用apt的时候&#xff0c;发现遇到了下面这些情况 后面听老师讲&#xff0c;还需要执行下面这个 但是我再次使用apt下载软件的时候&#xff0c;还是出现了下面这个情况 后面问了老师才知道是apt源的问题&#x…

解决Github打不开或速度慢的问题

一、原因 我们先分析一下Github在国内访问慢或有时候登陆不上去的问题原因&#xff1a;其实这都是因为我们访问github官网时是直接访问域名即github.com&#xff0c;那么中间有个域名通过DNS解析的过程&#xff0c;将域名解析为对应的ip地址&#xff0c;其实主要时间都是花在了…

【寻找one piece的算法之路】——双指针算法!他与她是否会相遇呢?

&#x1f490;个人主页&#xff1a;初晴~ &#x1f4da;相关专栏&#xff1a;寻找one piece的刷题之路 什么是双指针算法 双指针算法是一种常用的编程技巧&#xff0c;尤其在处理数组和字符串问题时非常有效。这种方法的核心思想是使用两个指针来遍历数据结构&#xff0c;这两…

学习记录:js算法(五十二):验证二叉搜索树

文章目录 验证二叉搜索树我的思路网上思路 总结 验证二叉搜索树 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的 左子树 只包含 小于 当前节点的数。 节点的 右子树 只包含 大于 当前节点的数。 所有…

【Python】AudioLazy:基于 Python 的数字信号处理库详解

AudioLazy 是一个用于 Python 的开源数字信号处理&#xff08;DSP&#xff09;库&#xff0c;设计目的是简化信号处理任务并提供更直观的操作方式。它不仅支持基础的滤波、频谱分析等功能&#xff0c;还包含了滤波器、信号生成、线性预测编码&#xff08;LPC&#xff09;等高级…

Mybatis框架梳理

Mybatis框架梳理 前言1.ORM2.模块划分2.1 ORM的实现2.2 SQL的映射2.3 插件机制2.4 缓存机制2.5 其他 3. 愿景 前言 如果让我聊一聊mybatis&#xff0c;我该怎么说呢&#xff1f;开发中时时刻刻都在用它&#xff0c;此时此刻&#xff0c;脑海中却只浮现ORM框架这几个字&#xff…

Linux --入门学习笔记

文章目录 Linux概述基础篇Linux 的安装教程 ⇒ 太简单了&#xff0c;百度一搜一大堆。此处略……Linux 的目录结构常用的连接 linux 的开源软件vi 和 vim 编辑器Linux 的关机、开机、重启用户登录和注销用户管理添加用户 ⇒ ( useradd 用户名 ) &#xff08; useradd -d 制定目…

【AIGC】内容创作——AI文字、图像、音频和视频的创作流程

我的主页&#xff1a;2的n次方_ 近年来&#xff0c;生成式人工智能&#xff08;AIGC&#xff0c;Artificial Intelligence Generated Content&#xff09;技术迅速发展&#xff0c;彻底改变了内容创作的各个领域。无论是文字、图像、音频&#xff0c;还是视频&#xff0c;A…

SPARK调优:AQE特性(含脑图总结)

学完AQE需要能够回答如下的几个问题&#xff1a; 什么是AQE&#xff1f;AQE的实现原理是什么&#xff1f;AQE的特性有哪些&#xff1f;使用什么参数实现&#xff1f;AQE每个特性可以解决什么问题&#xff1f;什么问题是AQE不能解决的 HL&#xff1a;学习脑图如下 SparkAQE是spa…

MES系统适用于哪些行业?MES系统对于企业的作用和价值

MES系统&#xff08;制造执行系统&#xff09;广泛应用于多个行业&#xff0c;并在这些行业中发挥着重要作用&#xff0c;为企业带来了显著的价值。以下是对MES系统适用行业及其对企业作用和价值的详细分析&#xff1a; 一、MES系统适用的行业 电子信息行业&#xff1a; 随着市…

大功率LED模块(5V STM32)

目录 一、介绍 二、模块原理 1.尺寸介绍 2.模块原理图 3.引脚描述 三、程序设计 main.c文件 timer.h文件 timer.c文件 四、实验效果 五、资料获取 项目分享 一、介绍 大功率LED模块是一种照明设备&#xff0c;它将大功率高亮度发光二极管(LED)集成在铝基板上&…

Linux学习笔记(二):深入理解用户管理、运行级别与命令行操作

Linux学习笔记&#xff08;二&#xff09;&#xff1a;深入理解用户管理、运行级别与命令行操作 Linux学习笔记&#xff08;一&#xff09;&#xff1a;Linux学习环境的安装及远程连接工具的使用 1. 用户管理 1.1 用户密码管理 创建用户密码 使用 passwd 命令可以为指定用户…

封装了一个iOS水平方向动态宽度layout

我们有时候会遇到这样的情形&#xff0c;就是需要展示一些动态的标签&#xff0c;宽度是动态的&#xff0c; 水平方向是一行&#xff0c;其实这种情况还是比较容易处理的&#xff0c;只是一下子想不起来&#xff0c; 这里做了一个相关的需求&#xff0c;将思路和代码记录下来&a…

第5章 总线与微命令实验

第5章 总线与微命令实验 5.1实验目的 &#xff08;1&#xff09;理解总线的概念和作用。 &#xff08;2&#xff09;连接运算器与存储器&#xff0c;熟悉计算机的数据通路。 &#xff08;3&#xff09;理解微命令与微操作的概念。 5.2实验要求 &#xff08;1&#xff09;做…

69 BERT预训练_by《李沐:动手学深度学习v2》pytorch版

系列文章目录 文章目录 系列文章目录NLP里的迁移学习Bert的动机Bert架构对输入的修改五、预训练任务1、2、3、 六、1、2、3、 七、1、2、3、 八、1、2、3、 NLP里的迁移学习 之前是使用预训练好的模型来抽取词、句子的特征&#xff0c;例如 word2vec 或语言模型这种非深度学习…

香酥胡麻饼 一口沦陷的传统美食

&#x1f96f;美食发现 | 胡麻饼&#xff0c;一口咬出的千年韵味&#x1f96f;&#x1f60b;宝子们&#xff0c;今天我要给大家分享一款超级有历史底蕴的美食 —— 食家巷胡麻饼。 ✨食家巷胡麻饼&#xff0c;那可是有着悠久历史的传统美食。在古代&#xff0c;它就备受人们喜…

【算法】链表:160.相交链表(easy)+双指针

系列专栏 《分治》 《模拟》 《Linux》 目录 1、题目链接 2、题目介绍 3、解法&#xff08;双指针&#xff09; 返回结果 算法正确性 时间复杂度 4、代码 1、题目链接 160. 相交链表 - 力扣&#xff08;LeetCode&#xff09; 2、题目介绍 ​ 3、解法&#xff08;…