C++刷怪笼(9)继承

目录

1.前言

2.正文

2.1继承的概念和定义

2.1.1继承的概念

2.1.2继承的定义

​编辑

2.1.3继承类模板

2.2基类和派生类间的转换

2.3继承中的作用域

2.3.1隐藏规则

2.4派⽣类的默认成员函数

2.4.1个常⻅默认成员函数

2.4.2实现⼀个不能被继承的类

2.5继承与友元

2.6继承与静态成员

2.7多继承及其菱形继承问题

7.1 继承模型

 2.7.2虚继承

2.8继承与组合

3.小结


1.前言

前面我们对C++的STL容器进行了一系列的学习,相信大家肯定有收获吧,接下来我们来学习C++三大特性中最具有创造性的一个特性--继承。

2.正文

2.1继承的概念和定义

2.1.1继承的概念

继承(inheritance)机制是⾯向对象程序设计使代码可以复⽤的最重要的⼿段,它允许我们在保持原有类特性的基础上进⾏扩展,增加⽅法(成员函数)和属性(成员变量),这样产⽣新的类,称派类。继承呈现了⾯向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的函数层次的复⽤,继承是类设计层次的复⽤。
下⾯我们看到没有继承之前我们设计了两个类Student和Teacher,Student和Teacher都有姓名/地址/电话/年龄等成员变量,都有identity⾝份认证的成员函数,设计到两个类⾥⾯就是冗余的。当然他们也有⼀些不同的成员变量和函数,⽐如⽼师独有成员变量是职称,学⽣的独有成员变量是号;学⽣的独有成员函数是学习,⽼师的独有成员函数是授课。

class Student
{ 
public:
    // 进⼊校园/图书馆/实验室刷⼆维码等⾝份认证
    void identity()
    {
        // ...
    } 
    // 学习
    void study()
    {
        // ...
    }
protected:
    string _name = "peter"; // 姓名
    string _address; // 地址
    string _tel; // 电话
    int _age = 18; // 年龄
    int _stuid; // 学号
};

class Teacher
{ 
public:
    // 进⼊校园/图书馆/实验室刷⼆维码等⾝份认证
    void identity()
    {
        // ...
    } 
    // 授课
    void teaching()
    {
        //...
    }
protected:
    string _name = "张三"; // 姓名
    int _age = 18; // 年龄
    string _address; // 地址
    string _tel; // 电话
    string _title; // 职称
};
int main()
{
    return 0;
}

下⾯我们公共的成员都放到Person类中,Student和teacher都继承Person,就可以复⽤这些成员,就不需要重复定义了,省去了很多⿇烦。

class Person
{ 
public:
    // 进⼊校园/图书馆/实验室刷⼆维码等⾝份认证
    void identity()
    {
        cout << "void identity()" <<_name<< endl;
    }
protected:
    string _name = "张三"; // 姓名
    string _address; // 地址
    string _tel; // 电话
    int _age = 18; // 年龄
};
class Student : public Person
{ 
public:
    // 学习
    void study()
    {
        // ...
    }
protected:
    int _stuid; // 学号
};
class Teacher : public Person
{ 
public:
    // 授课
    void teaching()
    {
        //...
    }
protected:
    string title; // 职称
};
int main()
{
    Student s;
    Teacher t;
    s.identity();
    t.identity();

    return 0;
}

2.1.2继承的定义

格式:下⾯我们看到Person是基类,也称作⽗类。Student是派⽣类,也称作⼦类。(因为翻译的原因,所以既叫基类/派⽣类,也叫⽗类/⼦类)

继承基类成员访问方式的变化:

1. 基类private成员在派⽣类中⽆论以什么⽅式继承都是不可⻅的。这⾥的不可⻅是指基类的私有成员还是被继承到了派⽣类对象中,但是语法上限制派⽣类对象不管在类⾥⾯还是类外⾯都不能去访问它。
2. 基类private成员在派⽣类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派⽣类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
3. 实际上⾯的表格我们进⾏⼀下总结会发现,基类的私有成员在派⽣类都是不可⻅。基类的其他成员在派⽣类的访问⽅式==Min(成员在基类的访问限定符,继承⽅式),public>protected>private。
4. 使⽤关键字class时默认的继承⽅式是private,使⽤struct时默认的继承⽅式是public,不过最好显⽰的写出继承⽅式。

5. 在实际运⽤中⼀般使⽤都是public继承,⼏乎很少使⽤protetced/private继承,也不提倡使⽤
protetced/private继承,因为protetced/private继承下来的成员都只能在派⽣类的类⾥⾯使⽤,实
际中扩展维护性不强。

// 实例演⽰三种继承关系下基类成员的各类型成员访问关系的变化
class Person
{ 
public :
    void Print ()
    {
        cout<<_name <<endl;
    }
protected :
    string _name ; // 姓名
    private :
    int _age ; // 年龄
};
    //class Student : protected Person
    //class Student : private Person
class Student : public Person
{ 
protected :
    int _stunum ; // 学号
};

2.1.3继承类模板

namespace ckl
{
    //template<class T>
    //class vector
    //{};

    // stack和vector的关系,既符合is-a,也符合has-a
    template<class T>
    class stack : public std::vector<T>
    { 
    public:
        void push(const T& x)
        {
            // 基类是类模板时,需要指定⼀下类域,
            // 否则编译报错:error C3861: “push_back”: 找不到标识符
            // 因为stack<int>实例化时,也实例化vector<int>了
            // 但是模版是按需实例化,push_back等成员函数未实例化,所以找不到
            vector<T>::push_back(x);
            //push_back(x);
        } 
        void pop()
        {
            vector<T>::pop_back();
        } 
        const T& top()
        {
            return vector<T>::back();
        } 
        bool empty()
        {
            return vector<T>::empty();
        }
    };
} 
int main()
{
    bit::stack<int> st;
    st.push(1);
    st.push(2);
    st.push(3);

    while (!st.empty())
    {
        cout << st.top() << " ";
        st.pop();
    } 
    return 0;
}


2.2基类和派生类间的转换

• public继承的派⽣类对象可以赋值给基类的指针/基类的引⽤。这⾥有个形象的说法叫切⽚或者切割。寓意把派⽣类中基类那部分切出来,基类指针或引⽤指向的是派⽣类中切出来的基类那部分。
• 基类对象不能赋值给派⽣类对象。
• 基类的指针或者引⽤可以通过强制类型转换赋值给派⽣类的指针或者引⽤。但是必须是基类的指针是指向派⽣类对象时才是安全的。这⾥基类如果是多态类型,可以使⽤RTTI(Run-TimeType Information)的dynamic_cast来进⾏识别后进⾏安全转换。

 

class Person
{ 
protected :
    string _name; // 姓名
    string _sex; // 性别
    int _age; // 年龄
};

class Student : public Person
{ 
public :
    int _No ; // 学号
};

int main()
{
    Student sobj ;
    // 1.派⽣类对象可以赋值给基类的指针/引⽤
    Person* pp = &sobj;
    Person& rp = sobj;
    // ⽣类对象可以赋值给基类的对象是通过调⽤后⾯会讲解的基类的拷⻉构造完成的
    Person pobj = sobj;
    //2.基类对象不能赋值给派⽣类对象,这⾥会编译报错
    sobj = pobj;

    return 0;
}

2.3继承中的作用域

2.3.1隐藏规则

1. 在继承体系中基类和派⽣类都有独⽴的作⽤域。
2. 派⽣类和基类中有同名成员,派⽣类成员将屏蔽基类对同名成员的直接访问,这种情况叫隐藏(在派⽣类成员函数中,可以使⽤基类::基类成员显⽰访问)

3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。
4. 注意在实际中在继承体系⾥⾯最好不要定义同名的成员。

// Student的_num和Person的_num构成隐藏关系,可以看出这样代码虽然能跑,但是⾮常容易混淆
class Person
{ 
protected :
    string _name = "⼩李⼦"; // 姓名
    int _num = 111; // ⾝份证号
};
    class Student : public Person
{ 
public:
    void Print()
    {
        cout<<" 姓名:"<<_name<< endl;
        cout<<" ⾝份证号:"<<Person::_num<< endl;
        cout<<" 学号:"<<_num<<endl;
    }
protected:
    int _num = 999; // 学号
};
int main()
{
    Student s1;
    s1.Print();

    return 0;
};

2.4派⽣类的默认成员函数

2.4.1个常⻅默认成员函数

6个默认成员函数,默认的意思就是指我们不写,编译器会变我们⾃动⽣成⼀个,那么在派⽣类中,这⼏个成员函数是如何⽣成的呢?
1. 派⽣类的构造函数必须调⽤基类的构造函数初始化基类的那⼀部分成员。如果基类没有默认的构造函数,则必须在派⽣类构造函数的初始化列表阶段显⽰调⽤。
2. 派⽣类的拷⻉构造函数必须调⽤基类的拷⻉构造完成基类的拷⻉初始化。
3. 派⽣类的operator=必须要调⽤基类的operator=完成基类的复制。需要注意的是派⽣类的
operator=隐藏了基类的operator=,所以显⽰调⽤基类的operator=,需要指定基类作⽤域
4. 派⽣类的析构函数会在被调⽤完成后⾃动调⽤基类的析构函数清理基类成员。因为这样才能保证派⽣类对象先清理派⽣类成员再清理基类成员的顺序。
5. 派⽣类对象初始化先调⽤基类构造再调派⽣类构造。
6. 派⽣类对象析构清理先调⽤派⽣类析构再调基类的析构。
7. 因为多态中⼀些场景析构函数需要构成重写,重写的条件之⼀是函数名相同(这个我们多态章节会讲解)。那么编译器会对析构函数名进⾏特殊处理,处理成destructor(),所以基类析构函数不加
virtual的情况下,派⽣类析构函数和基类析构函数构成隐藏关系。

解释如上图 。

class Person
{ 
public :
    Person(const char* name = "peter")
        : _name(name )
    {
        cout<<"Person()" <<endl;
    } 
    Person(const Person& p)
        : _name(p._name)
    {
        cout<<"Person(const Person& p)" <<endl;
    }
     Person& operator=(const Person& p )
    {
        cout<<"Person operator=(const Person& p)"<< endl;
        if (this != &p)
            _name = p ._name;
        return *this ;
} 

    ~Person()
    {
        cout<<"~Person()" <<endl;
    }
protected :
    string _name ; // 姓名
};

class Student : public Person
{ 
public :
    Student(const char* name, int num)
        : Person(name)
        , _num(num )
    {
            cout<<"Student()" <<endl;
    } 
    Student(const Student& s)
        : Person(s)
        , _num(s ._num)
    {    
        cout<<"Student(const Student& s)" <<endl ;
    } 
    Student& operator = (const Student& s )
    {
        cout<<"Student& operator= (const Student& s)"<< endl;
        if (this != &s)
        {
            // 构成隐藏,所以需要显⽰调⽤
            Person::operator =(s);
            _num = s ._num;
        } 
    return *this ;
    } 
    ~Student()
    {
        cout<<"~Student()" <<endl;
    }
protected :
    int _num ; //学号
};
int main()
{
    Student s1 ("jack", 18);
    Student s2 (s1);
    Student s3 ("rose", 17);
    s1 = s3 ;

    return 0;
}


2.4.2实现⼀个不能被继承的类

⽅法1:基类的构造函数私有,派⽣类的构成必须调⽤基类的构造函数,但是基类的构成函数私有化以后,派⽣类看不⻅就不能调⽤了,那么派⽣类就⽆法实例化出对象。
⽅法2:C++11新增了⼀个final关键字,final修改基类,派⽣类就不能继承了。
 

// C++11的⽅法
class Base final
{ 
public:
    void func5() { cout << "Base::func5" << endl; }
protected:
    int a = 1;
private:
    // C++98的⽅法
    /*Base()
    {}*/
};

class Derive :public Base
{
    void func4() { cout << "Derive::func4" << endl; }
protected:
    int b = 2;
};

int main()
{
    Base b;
    Derive d;

    return 0;
}

2.5继承与友元

友元关系不能继承,也就是说基类友元不能访问派生类私有和保护成员

class Student;
class Person
{ 
public:
    friend void Display(const Person& p, const Student& s);
protected:
    string _name; // 姓名
};
class Student : public Person
{ 
protected:
    int _stuNum; // 学号
};
void Display(const Person& p, const Student& s)
{
    cout << p._name << endl;
    cout << s._stuNum << endl;
} 
int main()
{
    Person p;
    Student s;
    // 编译报错:error C2248: “Student::_stuNum”: ⽆法访问 protected 成员
    // 解决⽅案:Display也变成Student 的友元即可
    Display(p, s);

    return 0;
}

2.6继承与静态成员

基类定义了static静态成员,则整个继承体系⾥⾯只有⼀个这样的成员。⽆论派⽣出多少个派生类,都只有⼀个static成员实例。

class Person
{ 
public:
    string _name;
    static int _count;
};

int Person::_count = 0;

class Student : public Person
{ 
protected:
    int _stuNum;
};

int main()
{
    Person p;
    Student s;
    // 这⾥的运⾏结果可以看到⾮静态成员_name的地址是不⼀样的
    // 说明派⽣类继承下来了,⽗派⽣类对象各有⼀份
    cout << &p._name << endl;
    cout << &s._name << endl;
    // 这⾥的运⾏结果可以看到静态成员_count的地址是⼀样的
    // 说明派⽣类和基类共⽤同⼀份静态成员
    cout << &p._count << endl;
    cout << &s._count << endl;
    // 公有的情况下,⽗派⽣类指定类域都可以访问静态成员
    cout << Person::_count << endl;
    cout << Student::_count << endl;

    return 0;
}

2.7多继承及其菱形继承问题
 

7.1 继承模型

单继承:⼀个派⽣类只有⼀个直接基类时称这个继承关系为单继承
多继承:⼀个派⽣类有两个或以上直接基类时称这个继承关系为多继承,多继承对象在内存中的模型是,先继承的基类在前⾯,后⾯继承的基类在后⾯,派⽣类成员在放到最后⾯。
菱形继承:菱形继承是多继承的⼀种特殊情况。菱形继承的问题,从下⾯的对象成员模型构造,可以看出菱形继承有数据冗余和⼆义性的问题,在Assistant的对象中Person成员会有两份。⽀持多继承就⼀定会有菱形继承,像Java就直接不⽀持多继承,规避掉了这⾥的问题,所以实践中我们也是不建议设计出菱形继承这样的模型的。
 

像这样的关系就是形成了菱形继承。

class Person
{ 
public:
    string _name; // 姓名
};

class Student : public Person
{ 
protected:
    int _num; //学号
};

class Teacher : public Person
{ 
protected:
    int _id; // 职⼯编号
};

class Assistant : public Student, public Teacher
{ 
protected:
    string _majorCourse; // 主修课程
};

int main()
{
    // 编译报错:error C2385: 对“_name”的访问不明确
    Assistant a;
    a._name = "peter";
    // 需要显⽰指定访问哪个基类的成员可以解决⼆义性问题,但是数据冗余问题⽆法解决
    a.Student::_name = "xxx";
    a.Teacher::_name = "yyy";

    return 0;
}

 2.7.2虚继承

很多⼈说C++语法复杂,其实多继承就是⼀个体现。有了多继承,就存在菱形继承,有了菱形继承就有菱形虚拟继承,底层实现就很复杂,性能也会有⼀些损失,所以最好不要设计出菱形继承。多继承可以认为是C++的缺陷之⼀,后来的⼀些编程语⾔都没有多继承,如Java。

class Person
{ 
public:
    string _name; // 姓名
    /*int _tel;
    int _age;
    string _gender;
    string _address;*/
    // ...
};

// 使⽤虚继承Person类
class Student : virtual public Person
{ 
protected:
    int _num; //学号
};

// 使⽤虚继承Person类
class Teacher : virtual public Person
{ 
protected:
    int _id; // 职⼯编号
};

// 教授助理
class Assistant : public Student, public Teacher
{ 
protected:
    string _majorCourse; // 主修课程
};

int main()
{
    // 使⽤虚继承,可以解决数据冗余和⼆义性
    Assistant a;
    a._name = "peter";

    return 0;
}


我们可以设计出多继承,但是不建议设计出菱形继承,因为菱形虚拟继承以后,⽆论是使⽤还是底层都会复杂很多。当然有多继承语法⽀持,就⼀定存在会设计出菱形继承,像Java是不⽀持多继承的,就避开了菱形继承。
 

class Person
{ 
public:
    Person(const char* name)
    :_name(name)
    {}
    string _name; // 姓名
};

class Student : virtual public Person
{ 
public:
    Student(const char* name, int num)
    :Person(name)
    ,_num(num)
    {}
protected:
    int _num; //学号
};

class Teacher : virtual public Person
{ 
public:
    Teacher(const char* name, int id)
    :Person(name)    
    , _id(id)
    {}
protected:
    int _id; // 职⼯编号
};

// 不要去玩菱形继承
class Assistant : public Student, public Teacher
{ 
public:
    Assistant(const char* name1, const char* name2, const char* name3)
        :Person(name3)
        ,Student(name1, 1)
        ,Teacher(name2, 2)
        {}
protected:
    string _majorCourse; // 主修课程
};

int main()
{
    // 思考⼀下这⾥a对象中_name是"张三", "李四", "王五"中的哪⼀个?
    Assistant a("张三", "李四", "王五");
    
    return 0;
}

2.8继承与组合

• public继承是⼀种is-a的关系。也就是说每个派⽣类对象都是⼀个基类对象。
• 组合是⼀种has-a的关系。假设B组合了A,每个B对象中都有⼀个A对象。
• 继承允许你根据基类的实现来定义派⽣类的实现。这种通过⽣成派⽣类的复⽤通常被称为⽩箱复⽤(white-boxreuse)。术语“⽩箱”是相对可视性⽽⾔:在继承⽅式中,基类的内部细节对派⽣类可
⻅。继承⼀定程度破坏了基类的封装,基类的改变,对派⽣类有很⼤的影响。派⽣类和基类间的依赖关系很强,耦合度⾼。
• 对象组合是类继承之外的另⼀种复⽤选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接⼝。这种复⽤⻛格被称为⿊箱复⽤(black-boxreuse),因为对象的内部细节是不可⻅的。对象只以“⿊箱”的形式出现。组合类之间没有很强的依赖关系,耦合度低。优先使⽤对象组合有助于你保持每个类被封装。
• 优先使⽤组合,⽽不是继承。实际尽量多去⽤组合,组合的耦合度低,代码维护性好。不过也不太那么绝对,类之间的关系就适合继承(is-a)那就⽤继承,另外要实现多态,也必须要继承。类之间的关系既适合⽤继承(is-a)也适合组合(has-a),就⽤组合。
 

// Tire(轮胎)和Car(⻋)更符合has-a的关系
class Tire {
protected:
    string _brand = "Michelin"; // 品牌
    size_t _size = 17; // 尺⼨
};

class Car {
protected:
    string _colour = "⽩⾊"; // 颜⾊
    string _num = "陕ABIT00"; // ⻋牌号
    Tire _t1; // 轮胎
    Tire _t2; // 轮胎
    Tire _t3; // 轮胎
    Tire _t4; // 轮胎
};

class BMW : public Car {
public:
    void Drive() { cout << "好开-操控" << endl; }
    };
    // Car和BMW/Benz更符合is-a的关系

class Benz : public Car {
public:
    void Drive() { cout << "好坐-舒适" << endl; }
};

template<class T>
class vector
{};
// stack和vector的关系,既符合is-a,也符合has-a

template<class T>
class stack : public vector<T>
{};

template<class T>
class stack
{ 
public:
    vector<T> _v;
};

int main()
{
    return 0;
}

3.小结

继承的大部分知识点我就已经阐述明白了,它在我们算法oj题上不怎么出现,但是在今后的工作项目中也还是至关重要的,大家也一定要把它吃透,以后在工作中才能得心应手,好了,今天的知识就讲述到这,下一篇我会对多态进行讲解,大家一键三连,跟着博主好好学~,我们下篇见

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

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

相关文章

QT中使用图表之QChart概述

在Qt中使用QChart类可以快速绘制一个图表出来&#xff0c;比如折线图、饼图、柱状图等 QChart类用来管理图表中的图形、图例、轴等 QChartView是专门用来显示图表的类&#xff0c;相当于一个QWidget或者窗口&#xff0c;用来显示QChart 即总的步骤就是 1、创建QChartView的…

codeforces _ 补题

C. Ball in Berland 传送门&#xff1a;Problem - C - Codeforces 题意&#xff1a; 思路&#xff1a;容斥原理 考虑 第 i 对情侣组合 &#xff0c;男生为 a &#xff0c;女生为 b &#xff0c;那么考虑与之匹配的情侣 必须没有 a | b &#xff0c;一共有 k 对情侣&#x…

零基础学西班牙语,柯桥专业小语种培训泓畅学校

No te comas el coco, seguro que te ha salido bien la entrevista. Ya te llamarn. 别瞎想了&#xff01;我保证你的面试很顺利。他们会给你打电话的。 这里的椰子是"头"的比喻。在西班牙的口语中&#xff0c;我们也可以听到其他同义表达&#xff0c;比如&#x…

一、开发环境的搭建

环境搭建步骤&#xff1a; 下载软件安装软件运行软件 其他&#xff1a; Visual studio 安装包文件&#xff1a;https://www.alipan.com/s/nd5RgzD4e3b 下载软件 在浏览器中搜索Visual studio&#xff0c;选择如图的选项 点击该区域&#xff0c;进入该页面&#xff0c;【或…

SSH免密钥登录

1: 用 ssh-key-gen 在本地主机上创建公钥和密钥 winr cmd 打开控制台 ssh-keygen -t rsa 一直按enter 2: 用 ssh-copy-id 把公钥复制到远程主机上 user 是用户名 remote_host是远程主机 ssh-copy-id -i ~/.ssh/id_rsa.pub userremote_host 3: 直接登录远程主机&#xf…

对外部供应商依赖带来的战略限制分析

当企业过分依赖单一或少数供应商时&#xff0c;一旦这些供应商出现问题&#xff0c;如生产延误、质量问题或财务困难&#xff0c;企业的运营将受到严重影响。例如&#xff0c;2020年的新冠疫情期间&#xff0c;许多企业因为供应商无法按时交货而面临生产停滞&#xff0c;导致巨…

Windows11家庭版安装Docker Desktop软件教程

下载Windows安装包 我们建议将源代码和其他数据绑定到 Linux 容器中时,将其存储在 Linux 文件系统中,而不是 Windows 文件系统中。 docker官网首页https://www.docker.com/ (需要科学上网)下载Windows版本的Docker Desktop。 或者使用已经下载好的Docker Desktop 安装包…

理解ADC:为什么量化噪声也会产生谐波?附带介绍 Dither(抖动)

前言 今天继续从经典的 ADI 《MT-001》说起&#xff0c;通常情况下量化噪声是白噪声&#xff0c;但如果量化噪声与输入信号之间存在相关性&#xff0c;就不能被当做白噪声对待。 文中举了一个有意思的例子&#xff1a;理想 ADC 的采样频率为 80 MSPS &#xff0c;一种情况输入…

外包干了7天,技术明显退步。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;22年通过校招进入南京某软件公司&#xff0c;干了接近2年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了2年的功能测试&…

vue组件在项目中的常用业务逻辑(1)

若要使用一个组件&#xff08;已有基本结构&#xff09; 1.在api>index.js获取接口数据&#xff08;这里是模拟数据&#xff09; 2.去vuex仓库&#xff08;store>home.js&#xff09;存储数据&#xff08;state mutations actions三连环&#xff09; &#xff08;准备…

Linux网络命令:系统中用于显示和操作 ARP缓存表的命令arp详解

目录 一、概述 二、用法 1、基本语法 2、常用选项 3、获取帮助 三、示例 1. 显示所有 ARP 表项 2. 以数字形式显示 IP 地址 3. 删除指定的 ARP 表项 4. 添加一个静态 ARP 表项 5. 显示详细信息 四、详细说明 1、ARP 缓存表 2、静态 ARP 表项 3、动态 ARP 表项 五、常…

如何在短时间内入门并掌握深度学习?

如何在短时间内快速入门并掌握深度学习&#xff0c;是很多读者的困惑——晦涩难懂的数学 知识、复杂的算法、烦琐的编程……深度学习虽然让无数读者心怀向往&#xff0c;却也让不少人望而生畏&#xff0c;深感沮丧&#xff1a;时间没少花&#xff0c;却收效甚微。 如何才能更好…

图像分割从基础到进阶:阈值化、K-means和Mean-Shift算法的应用

图像分割是计算机视觉中的一项关键技术&#xff0c;用来将图像划分为若干个 有意义 的区域&#xff0c;以便后续的图像处理和分析工作。根据任务的不同&#xff0c;图像分割可以进一步细分为语义分割、实例分割和全景分割&#xff1a; 语义分割 (Semantic Segmentation) 对图像…

JavaEE进阶----18.<Mybatis补充($和#的区别+数据库连接池)>

详解了 1.$和#的区别 2.数据库连接池。 3.简单了解MySQL企业开发规范 一、Mybatis面试题&#xff1a;$和#的区别是什么&#xff1f; MyBatis 参数赋值有两种方式&#xff0c;咱们前面使用了 #{} 进行赋值&#xff0c;接下来我们看下二者的区别。 1.1 #是预编译SQL&#xff0c;$…

瑞格智慧心理服务平台 NPreenSMSList.asmx sql注入漏洞复现

0x01 产品描述&#xff1a; ‌ 瑞格智慧心理服务平台‌是一个集心理测评、心理咨询、心理危机干预、心理放松训练等功能于一体的综合性心理健康服务平台。该平台由北京瑞格心灵科技有限公司开发&#xff0c;旨在为用户提供全方位的心理健康服务。0x02 漏洞描述&#xff1a;…

Webserver(1.8)操作函数

目录 文件属性操作函数access函数chmod函数chown函数truncate函数 目录操作函数mkdir函数rmdir函数rename函数chdir函数*getcwd函数 目录遍历函数*opendir函数*readdir函数closedir函数 dup、dup2函数dupdup2 fcntl函数 文件属性操作函数 access函数 判断某个文件是否有某个权…

(49)MATLAB实现迫零均衡器原理与代码

文章目录 前言一、迫零均衡器设计说明二、迫零均衡器MATLAB源代码1.函数说明2.代码实现3.辅助函数 前言 使用MATLAB实现迫零均衡器。给出完整的MATLAB设计源代码。 一、迫零均衡器设计说明 理想的迫零均衡器有无限多个抽头权系数&#xff0c;是不能实现的&#xff0c;本文考虑…

springboot揭秘00-基于java配置的spring容器

文章目录 【README】【1】基本概念&#xff1a;Configuration与Bean【2】使用AnnotationConfigApplicationContext实例化spring容器【2.1】使用java配置简单构建spring容器【2.1.1】AnnotationConfigApplicationContext与Component及JSR-330注解类一起使用 【2.2】使用register…

线程和进程延续

1.线程和进程启动终止方式 1.创建子进程&#xff0c;子线程 2.退出进程/线程 3.回收僵尸进程资源 / 回收线程资源 4.进程终止函数 / 线程清理函数 2.线程状态切换 pthread_create()变为就绪态&#xff0c;调度后成为运行态&#xff0c;pthread_join()成为阻塞态…

为微信小程序换皮肤之配置vant

微信小程序自带的控件虽然具有很好的通用性和简洁性&#xff0c;但在面对一些复杂的交互场景和个性化的设计需求时&#xff0c;可能会显得力不从心。其功能的相对基础使得开发者在实现诸如多步骤复杂表单提交、实时数据交互与可视化展示、高度定制化的界面布局等方面&#xff0…