当前位置: 首页 > news >正文

[C++随想录] 继承

继承

  • 继承的引言
  • 基类和子类的赋值转换
  • 继承中的作用域
  • 派生类中的默认成员函数
  • 继承与友元
  • 继承与静态成员
  • 多继承的结构
  • 棱形继承的结构
  • 棱形虚拟继承的结构
  • 继承与组合

继承的引言

  1. 概念
    继承(inheritance)机制是面向对象程序设计使代码可以 复用的最重要的手段,它允许程序员在保
    持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象
    程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继 承是类设计层次的复用。
  2. 定义
class People
{
public:People(string name = "John", int age = 18){_name = name;_age = age;}void print() {cout << "姓名->" << _name << endl;cout << "年龄->" << _age << endl;}protected:int _age ;string _name;
};class Student : public People
{
public:Student(string name = "muyu", int age = 20, string id = "9210401227"):People(name, age){_id = id;}protected:string _id;
};class Teacher : public People
{
public:Teacher(){People::_name = "mutong";People::_age = 22;}protected:int _JobNumber;
};int main()
{People p;p.print();cout << endl;Student s;s.print();cout << endl;Teacher t;t.print();return 0;
}

运行结果:

姓名->John
年龄->18姓名->muyu
年龄->20姓名->mutong
年龄->22
  1. 解释 class Student : public People

    People类是 父类/ 基类, Student类是 子类/ 派生类
    Student类继承People类的本质就是 复用Student 对象可以使用 People类里面的成员
    成员包括 成员变量 和 成员函数.
    成员变量是在对象空间内的, 而成员函数是不在对象空间内的, 属于整个类.
    成员的 访问限定符 有三种 public, protected, private
    继承方式不同 && 基类成员的访问限定符不同决定了基类的成员在派生类中的存在情况

  2. 继承的方式
    继承方式有三种: public, protected, private
    成员的 限定符 有三种 public, protected, private
    所以, 一共有 九种继承方式 👇👇👇

    1. 基类中的private成员, 在派生类中都是 不可见的
      • 不可见 和 private成员是不一样的, private成员是 类里面可以访问, 类外面不可访问, 不可见是 类里面看不见/ 不可访问, 类外面不可访问
    2. 其余继承方式, 派生类中的情况是 继承方式 和 类成员访问限定符中 权限小的那一个
      • 权限的大小: public > protected > private
    3. 父类如果是 class, 默认继承是 私有继承, 父类如果是 struct, 默认继承是 公有继承. 不过建议显示继承方式
    4. 常用的继承方式为 图中绿色的区域 ⇐ 继承的本质是 复用, 私有继承 和 基类中的私有成员在继承中是没有复用的意义的.
  3. 为什么 派生类没有 print函数 , 但能调用 print函数?
    我们可以认为 子类对象里面包含两个部分: 父类对象成员变量 + 子类本身成员变量

    子类对象中的 成员变量 = 自己本身的成员变量 + 父类的成员变量 (受访问限定符 和 继承方式共同限制)
    子类对象中的 成员函数 = 自己本身的成员函数 + 父类的成员函数 (受访问限定符 和 继承方式共同限制)
    print函数 是公有继承 && 访问限定符是公有 ⇒ 子类对象可以调用

  4. 为什么在 Teacher类中 可以People::_name = "mutong";
    我们已经知道了 派生类对象的基本结构了.
    那么派生类对象在 初始化阶段, 即调用默认构造 是先父类还是先子类呢?
    通过调试, 我们发现: 子类对象调用构造函数的时候, 先调用父类的默认构造函数去初始化子类中父类对象的那一部分, 然后在调用子类对象的默认构造函数
    Person类中有默认构造函数, 但是我们想改变一下 Teacher类对象中的 关于父类对象的那一部分, 那我们该怎么做呢?
    首先, 我们不能直接写

_name = "mutong";
_age = 22;

因为受 的影响, 域是编译器在编译阶段查找变量的规则.
虽然, 我们可以认为子类对象中有 父类对象成员 + 子类对象成员, 但彼此是 独立的.
调用默认构造函数还是去 Person类中去调用
编译器在 编译阶段默认查找的顺序是 局部域 , 子类域, 父类域, 全局域
我们在子类中去给父类对象成员赋值 ⇒ 我们应该告诉编译器, 这个变量直接去父类中去查找就OK
即, 这个时候我们要用 Person(父类)::

  1. 为什么在 Student类中 可以 :People(name, age)
    子类对象调用构造函数的时候, 先调用父类的默认构造函数去初始化子类中父类对象的那一部分, 然后在调用子类对象的默认构造函数.
    那么如果 父类对象没有默认构造函数呢?
    我们就需要 在子类的初始化列表处 显示调用父类的构造

基类和子类的赋值转换

int main()
{People p;Student st;st = p; // errorp = st; // 可以进行转换return 0;
}
  • 父类对象 不能 赋值给子类对象, 而子类对象 可以 赋值给父类对象
    可以这样想: 子类对象的成员 > 父类对象的成员可以 变小一点, 但不能变大一点

父类对象 = 子类对象, 属于不同类型之间的赋值 ⇒ 一般都会发生 类型转换 ⇒ 类型转换, 那就意味着要产生 临时常量拷贝. 但结果真的如我们想的这般吗?

  • 验证 父类对象 = 子类对象 是否有临时常量拷贝
    拷贝是 常量的 ⇒ 要进行区分, 我们可以使用 引用 &
    如果生成了临时拷贝, 我们用普通引用 就会导致 权限的放大 , 就会报错
    如果没有生成临时拷贝, 我们用普通引用, 就是 权限的平移, 就不会报错
int main()
{// 类型转换int i = 0;double d = i;// double& dd = i // errorconst double& dd = i;// 赋值兼容转换Student st;People ps = st;People& p = st;return 0;
}

派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫 切片 或者切割 . 寓意把派生类中父类那部分切来赋值过去

🗨️那么这个切片是怎样完成的呢?

继承中的作用域

🗨️在继承过程中, 可能会出现 父类中的成员名 和 子类中的成员名相同的情况, 那么派生类对象调用该成员会是怎样的情况呢?

  • 先看下面的代码:
class People
{
public:People(string name = "John", int age = 18){_name = name;_age = age;}void print() {cout << "class People" << endl;}protected:int _age ;string _name;
};class Student : public People
{
public:Student(string name = "muyu", int age = 20, string id = "9210401227"):People(name, age){_id = id;}void print(){cout << "class Student : public People" << endl;}protected:string _id;
};void test1()
{Student st;st.print();
}int main()
{test1();return 0;
}

运行结果:

class Student : public People

父类和子类中都有 print函数, 通过结果显示 派生类内部的print函数
这是因为 , 跟上面的People::_name = "muyu";是一样的道理
那么, 如果我们非要通过派生类对象 调用基类中的print函数呢?👇👇👇

void test1()
{Student st;st.People::print();
}

总结:

  1. 子类和父类中的成员尽量不同名!
  2. 上面的例子, 子类和父类有同名的成员, 子类隐藏父类的成员, 这种关系叫做 隐藏/ 重定义
    • 注意: 隐藏 != 重载
      重载的前提条件是 同一作用域, 而隐藏是 父类和子类成员同名
    • 隐藏 != 重写
      隐藏是 子类中同名成员隐藏父类中同名成员, 而重写是 子类中重写父类有关函数的实现

派生类中的默认成员函数

6个默认成员函数,“默认”的意思就是指我们不写,编译器会变我们自动生成一个,那么在派生类
中,这几个成员函数是如何生成的呢?

  1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认 的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。
  2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
  3. 派生类的operator=必须要调用基类的operator=完成基类的复制。
  4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能
    保证派生类对象先清理派生类成员再清理基类成员的顺序。
  5. 派生类对象初始化先调用基类构造再调派生类构造。
  6. 派生类对象析构清理先调用派生类析构再调基类的析构。
  7. 因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同(这个我们后面会讲
    解)。那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加
    virtual的情况下,子类析构函数和父类析构函数构成隐藏关系
class Person
{
public:Person(string name = "muyu", int age = 20):_name(name),_age(age){cout << "Person()" << endl;}Person(const Person& tem){_name = tem._name;_age = tem._age;cout << "Person(const Person& tem)" << endl;}Person& operator=(const Person& tem){_name = tem._name;_age = tem._age;return *this;cout << "Person& operator=(Person& tem)" << endl;}~Person(){cout << "~Person()" << endl;}protected:string _name;int _age;
};class Student : public Person
{
public:Student(const string name,const int age, const int num): Person(name,age), _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; //学号
};void test2()
{Student st1("牧童", 20, 20230101);Student st2(st1);Student st3("沐雨", 18, 20230102);st3 = st1;}int main()
{// test1();test2();return 0;
}

运行结果:

Person()
Student()
Person(const Person& tem)
Student(const Student& s)
Person()
Student()
Student& operator= (const Student& s)
~Student()
~Person()
~Student()
~Person()
~Student()
~Person()

🗨️其他函数都是 先父类, 后子类, 唯独 析构函数 先子类后父类?

  • 首先, 构造函数是 先父类, 后子类
    , 先进后出 ⇒ 析构的时候, 先子类, 后父类.
    其次, 父类可以调用子类的成员, 而子类不能调用父类的成员
    如果先析构父类, 如果子类对象还想调用父类的成员,那就完蛋了!

🗨️在子类的析构函数中, 调用父类的析构函数

  • 首先,
	~Student(){~Person(); // 提示有一个重载cout << "~Student()" << endl;}

纳闷? 这个还能有重载?
因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同(这个我们后面会讲
解)。那么编译器会对析构函数名进行特殊处理,处理成destrutor().
那么子类和父类中的 析构函数名 都是 destruction ⇒ 那么就构成了隐藏关系
那么我们在子类中调用父类的析构函数应该如下:

	~Student(){Person::~Person();cout << "~Student()" << endl;}

结果如下:

  • 编译器默认帮我们 先调用了父类的析构函数不信任我们用户, 由编译器自己完成

继承与友元

基类的友元, 派生类不会继承, 即基类的友元不能访问 子类中的 私有和保护成员

// 类的声明
class Student;class Person
{
public:friend void Display(const Person& p, const Student& s);protected:string _name; // 姓名};class Student : public Person
{
public:// friend void Display(const Person& p, const Student& s);
protected:int _stuNum; // 学号};void Display(const Person& p, const Student& s)
{cout << p._name << endl;cout << s._stuNum << endl; // error: “Student::_stuNum”: 无法访问 protected 成员(在“Student”类中声明)
}void test3()
{Person p;Student s;Display(p, s);
}int main()
{test3();return 0;
}

解决方法就是: 让 Display函数也充当 子类的友元👇👇👇

class Student : public Person
{
public:friend void Display(const Person& p, const Student& s);
protected:int _stuNum; // 学号};

继承与静态成员

基类中定义了一个静态成员, 则在整个继承体系中, 仅此一份. 子类不会单独拷贝一份, 继承的是使用权

🗨️只创建子类对象, 问一共创建了多少个子类对象?

  • 1. 可以在子类的默认构造中创建一个静态成员变量.
class A
{
public:A(){}
};class B :public A
{
public:B(){_count++;}
public:static int _count;
};int B::_count = 0;void test4()
{B b1;B b2;B b3;B b4;B b5;B b6;cout << "子类中的个数->" << B::_count << endl;}int main()
{test4();return 0;
}

运行结果:

子类中的个数->6
  1. 可以在父类的默认构造中创建一个静态成员变量.
class A
{
public:A(){++_count;}
public:static int _count;
};int A::_count = 0;class B :public A
{};void test4()
{B b1;B b2;B b3;B b4;B b5;B b6;cout << "子类的个数->" << A::_count << endl;}int main()
{test4();return 0;
}

运行结果:

子类中的个数->6

多继承的结构

一个子类只有一个直接父类, 叫做 单继承

一个子类有两个及以上的父类, 叫做 多继承

  1. 单继承的结构

    其实在 内存中不是这样 "点开" 的关系, 而是连续的空间

  2. 多继承的机构

    当然, 也是连续的空间

棱形继承的结构

多继承会有一种情况是 棱形继承

D继承B和C, B和C又同时继承A ⇒ 就会导致D对象中有两个A对象成员
在这里插入图片描述

这样就会导致 冗余性和二义性

其实, 解决 访问不明确/ 二义性 可以使用 基类::

但是 内存中D还是存储了两份 A类对象 造成的数据冗余性问题还没解决呢?

棱形虚拟继承的结构

棱形虚拟继承解决的就是 数据冗余性 和 二义性的问题


通过 内存窗口, 我们发现:

  1. 把A从B 和 C中抽出来了, 让A既不属于B, 也不属于C
  2. B和C类中多了一个位置出来
  • B和C类中多了一个位置的用处是什么?

    我们发现: 地址指向的空间第一个位置是 0, 第二个位置分别是 20(十六进制转二进制) 和 12(十六进制转二进制)

    虽然, 把A类单独放在一个空间, 但 A类中的成员还是B和C类得一部分 =>
    这里是通过了B和C的两个指针,指向的一张表。这两个指针叫 虚基表指针,这两个表叫 虚基表。虚基表中存的 偏移量 。通过偏移量可以找到下面的A。

那么这个时候, 我们修改A类的对象, 就不会有 冗余性和二义性的问题了👇👇👇

继承与组合

继承是一种 is-a的关系, 是一种 白箱复用, 子类跟父类之间的 耦合度高
对象组合是一种 has-a的关系, 是一种 黑箱复用, 耦合度低

  • is-a 和 has-a
    is-a,就表示 子类是一个特殊的父类
    has-a, 就表示 A对象中有B对象

  • 白箱复用 和 黑箱复用
    白箱复用, 透明的, 即 子类知道父类内部的细节, 方法的实现
    黑箱复用, 不透明的, 即 对象之间不知道彼此的内部的细节

  • 耦合度
    打个比方:
    父类A中的成员 有20个是public, 80个是protected的; 派生类是public继承
    那么在派生类B中, A的成员都是可见的 ⇒ 耦合度是 100%
    同样的,
    A对象中的成员, 有20个是public, 80个是protected的;
    那么B对象想用A对象里面的成员, 只能使用 20个public的成员 ⇒ 耦合度是 20%

🗨️那对象组合这么好, 我们就用对象组合, 不用继承了是吧?

  • 首先, 存在即合理 ⇒ 全部都这样, 或者全部都那样的想法就是错误的
    1. 合理使用: 符合is-a 关系的就使用 继承; 符合 has-a关系就使用 对象组合; 如果 既符合has-a, 又符合 is-a关系使用 对象组合
    2. 实现 多态 , 必须使用继承

学后反思:

  1. 什么是菱形继承?菱形继承的问题是什么?
  2. 什么是菱形虚拟继承?如何解决数据冗余和二义性的
  3. 继承和组合的区别?什么时候用继承?什么时候用组合?

与朋友论学,须委曲谦下,宽以居之。 — — 王阳明
译文:与朋友谈论学问,必须婉转曲从谦虚下问,与之宽和相处

相关文章:

[C++随想录] 继承

继承 继承的引言基类和子类的赋值转换继承中的作用域派生类中的默认成员函数继承与友元继承与静态成员多继承的结构棱形继承的结构棱形虚拟继承的结构继承与组合 继承的引言 概念 继承(inheritance)机制是面向对象程序设计使代码可以 复用的最重要的手段&#xff0c;它允许程序…...

ARM-day9

按键控制小灯、蜂鸣器、风扇&#xff0c;按一次启动&#xff0c;第二次关闭 key_it.c #include "key_it.h"//按键3的配置 void key3_it_config() {//RCC使能GPIOF时钟RCC->MP_AHB4ENSETR | (0x1<<5);GPIOF->MODER & (~(0x3<<16));EXTI->E…...

2386: [余姚2015] 幸运数字(luck)

目录 题目描述 输入 输出 样例输入 样例输出 提示 来源: 代码&#xff1a; 题目描述 今年圣诞节&#xff0c;小明收到了很多礼物&#xff0c;每个礼物上都有一个数字&#xff0c;表示对小明的祝福。可是小明有自己的想法&#xff0c;对小明来说&#xff0c;4或者7的倍数…...

【JUC系列-13】深入理解DelayQueue延迟队列的底层原理

JUC系列整体栏目 内容链接地址【一】深入理解JMM内存模型的底层实现原理https://zhenghuisheng.blog.csdn.net/article/details/132400429【二】深入理解CAS底层原理和基本使用https://blog.csdn.net/zhenghuishengq/article/details/132478786【三】熟练掌握Atomic原子系列基本…...

Leetcode---365周赛

题目列表 2873. 有序三元组中的最大值 I 2874. 有序三元组中的最大值 II 2875. 无限数组的最短子数组 2876. 有向图访问计数 一、有序三元组中的最大值I 看一眼该题的数据范围&#xff0c;直接三层for循环暴力枚举&#xff0c;时间复杂度O(n^3)&#xff0c;代码如下 class…...

Java使用opencv实现人脸识别、人脸比对

1. opencv概述 OpenCV是一个开源的计算机视觉库&#xff0c;它提供了一系列丰富的图像处理和计算机视觉算法&#xff0c;包括图像读取、显示、滤波、特征检测、目标跟踪等功能。 opencv官网&#xff1a;https://opencv.org/ opencv官网文档&#xff1a;https://docs.opencv.or…...

Redis HyperLogLog的使用

Redis HyperLogLog知识总结 一、简介二、使用 一、简介 Redis HyperLogLog是一种数据结构&#xff0c;用于高效地计算基数&#xff08;集合中唯一元素的数量&#xff09;。它的主要作用是用于在内存中高效地存储和计算大量数据的基数&#xff0c;而无需完全存储所有的数据。Hy…...

Apisix-Ingress服务发现详解

apisix Apache APISIX 是一个基于微服务 API 网关&#xff0c;其不仅可以处理南北向的流量&#xff0c;也可以处理东西向的流量即服务之间的流量。Apache APISIX 集成了控制面板和数据面&#xff0c;与其他 API 网关相比&#xff0c;Apache APISIX 的上游、路由、插件全是动态的…...

spring6-事务

文章目录 1、JdbcTemplate1.1、简介1.2、准备工作1.3、实现CURD①装配 JdbcTemplate②测试增删改功能③查询数据返回对象④查询数据返回list集合⑤查询返回单个的值 2、声明式事务概念2.1、事务基本概念①什么是事务②事务的特性 2.2、编程式事务2.3、声明式事务 3、基于注解的…...

JavaFx学习问题2--音频、视频播放失败情况

文章目录 一、路径注意事项&#xff1a;① 用相对路径的时候别忘了前面的斜杠② uri问题 二、播放不了的问题① 获取的媒体文件路径本身就是不对的② 必须是uri③ 特殊情况 额外收获: 一、路径注意事项&#xff1a; 完整代码如下: import javafx.application.Application; im…...

第55节—— redux-toolkit中的createReducer——了解

一、概念 当我们使用 Redux 开发应用程序时&#xff0c;一个非常重要的概念就是 reducer。一个 reducer 是一个纯函数&#xff0c;它接受先前的状态和一个动作&#xff0c;然后返回一个新状态。每个动作都会引起状态的变化&#xff0c;从而使应用程序状态管理更加清晰和可控。…...

JUC并发编程——JUC并发编程概述及Lock锁(重点)(基于狂神说的学习笔记)

基于bilibili狂神说JUC并发编程视频所做笔记 概述 什么是JUC JUC时java.util工具包中的三个包的简称 java.util.concurrent java.util.concurrent.atomic java.util.concurrent.locks 业务&#xff1a;普通的线程代码中&#xff0c;我们常使用Runnable接口 但Runnable没有返…...

深入了解 Java 中的时间信息定义、转换、比较和操作

1. 简介 在过去的传统Java日期处理中&#xff0c;经常面临着一些问题。比如&#xff0c;java.util.Date和java.util.Calendar在表示日期和时间时存在着一些奇怪的行为&#xff0c;如月份从0开始计数、对日期进行格式化的方式繁琐不直观等。这些问题给开发带来了一定的困扰。 …...

2023年中国智能矿山发展历程及趋势分析:智能矿山健康有序发展[图]

智能矿山系统对矿山生产提质增效的效果已经开始显现&#xff1a;对不合规、有风险的行动进行及时预警&#xff0c;减少安全事故发生概率&#xff0c;避免因停产整顿产生的巨额亏损&#xff1b;精细化管理整个生产流程&#xff0c;避免过往传统粗放的流程导致的浪费&#xff0c;…...

acwing算法基础之基础算法--整数离散化算法

目录 1 知识点2 模板 1 知识点 整个范围很大&#xff0c;但存在的数据点很少。比如从 − 1 0 9 -10^9 −109到 1 0 9 10^9 109&#xff0c;但总共只有 1 0 6 10^6 106个数。 可以采用离散化的思想来做&#xff0c;即将离散的大数值映射成连续的小数值&#xff08;一般是 1 , …...

基于SSM框架的安全教育平台

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…...

Kafka生产者使用案例

1.生产者发送消息的过程 首先介绍一下 Kafka 生产者发送消息的过程&#xff1a; 1)Kafka 会将发送消息包装为 ProducerRecord 对象&#xff0c; ProducerRecord 对象包含了目标主题和要发送的内容&#xff0c;同时还可以指定键和分区。在发送 ProducerRecord 对象前&#xff0c…...

EasyX图形库实现贪吃蛇游戏

⭐大家好&#xff0c;我是Dark Falme Masker,学习了动画制作及键盘交互之后&#xff0c;我们就可以开动利用图形库写一个简单的贪吃蛇小游戏&#xff0c;增加学习乐趣。 ⭐专栏&#xff1a;EasyX部分小游戏实现详细讲解 最终效果如下 首先包含头文件 #include<stdio.h> #…...

利用 Amazon CodeWhisperer 激发孩子的编程兴趣

我是一个程序员&#xff0c;也是一个父亲。工作之余我会经常和儿子聊他们小学信息技术课学习的 Scratch 和 Kitten 这两款图形化的少儿编程工具。 我儿子有一次指着书房里显示器上显示的 Visual Studio Code 问我&#xff0c;“为什么我们上课用的开发界面&#xff0c;和爸爸你…...

2023年中国分子筛稀土催化材料竞争格局及行业市场规模分析[图]

稀土催化材料能够起到提高催化剂热稳定性、催化剂活性、催化剂储氧能力&#xff0c;以及减少贵金属活性组分用量等作用&#xff0c;广泛应用于石油化工、汽车尾气净化、工业废气和人居环境净化、燃料电池等领域。 2015-2023年中国稀土催化材料规模及预测 资料来源&#xff1a;…...

vue3插件——vue-web-screen-shot——实现页面截图功能

最近在看前同事发我的vue3框架时&#xff0c;发现他们有个功能是要实现页面截图功能。 vue3插件——vue-web-screen-shot——实现页面截图功能 效果图如下&#xff1a;1.操作步骤1.1在项目中添加vvue-web-screen-shot组件1.2在项目入口文件导入组件——main.ts1.3在需要使用的页…...

简单总结Centos7安装Tomcat10.0版本

文章目录 前言JDK8安装部署Tomcat 前言 注意jdk与tomcat的兼容问题&#xff0c;其他的只要正确操作一般问题不大 Tomcat 是由 Apache 开发的一个 Servlet 容器&#xff0c;实现了对 Servlet 和 JSP 的支持&#xff0c;并提供了作为Web服务器的一些特有功能&#xff0c;如Tomca…...

ffmpeg中AVCodecContext和AVCodec的关系分析

怎么理解AVCodecContext和AVCodec的关系 AVCodecContext和AVCodec是FFmpeg库中两个相关的结构体&#xff0c;它们在音视频编解码中扮演着不同的角色。 AVCodecContext&#xff1a;是编解码器上下文结构体&#xff0c;用于存储音视频编解码器的参数和状态信息。它包含了进行音视…...

2023年中国门把手产量、销量及市场规模分析[图]

门把手行业是指专门从事门把手的设计、制造、销售和安装等相关业务的行业。门把手是门窗装饰硬件的一种&#xff0c;用于开启和关闭门窗&#xff0c;同时也具有装饰和美化门窗的作用。 门把手行业分类 资料来源&#xff1a;共研产业咨询&#xff08;共研网&#xff09; 随着消…...

HTML 核心技术点基础详细解析以及综合小案例

核心技术点 网页组成 排版标签 多媒体标签及属性 综合案例一 - 个人简介 综合案例二 - Vue 简介 02-标签语法 HTML 超文本标记语言——HyperText Markup Language。 超文本&#xff1a;链接 标记&#xff1a;标签&#xff0c;带尖括号的文本 标签结构 标签要成…...

BAT学习——批处理脚本(也称为BAT文件)常用语法元素与命令

批处理脚本&#xff08;也称为BAT文件&#xff09;使用Windows的批处理语言编写&#xff0c;它具有一些常用的语法元素和命令。以下是一些BAT编程的常用语法元素和命令&#xff1a; 命令行命令&#xff1a; 批处理脚本通常包含一系列Windows命令&#xff0c;例如echo&#xff0…...

AMD AFMF不但能用在游戏,也适用于视频

近期AMD发布了AMD Software Adrenalin Edition预览版驱动程序&#xff0c;增加了对平滑移动帧&#xff08;AMD Fluid Motion Frames&#xff0c;AFMF&#xff09;功能的支持&#xff0c;也就是AMD的“帧生成”技术&#xff0c;与DLSS 3类似&#xff0c;作为FidelityFX Super Re…...

CSS 常用样式浮动属性

一、概述 CSS 中&#xff0c;浮动属性的作用是让元素向左或向右浮动&#xff0c;使其他元素围绕它排布&#xff0c;常用的浮动属性有以下几种&#xff1a; float: left; 使元素向左浮动&#xff0c;其他元素从右侧包围它。 float: right; 使元素向右浮动&#xff0c;其他元素…...

Linux引导故障排除:从问题到解决方案的详细指南

1 BIOS初始化 通电->对硬件检测->初始化硬件时钟 2 磁盘引导及其修复 2.1 磁盘引导故障 磁盘主引导记录&#xff08;MBR&#xff09;是在0磁道1扇区位置&#xff0c;446字节。 MBR作用&#xff1a;记录grub2引导文件的位置 2.2 修复 步骤&#xff1a;1、光盘进…...

【vim 学习系列文章 6 -- vim 如何从上次退出的位置打开文件】

文章目录 1.1 vim 如何从上次退出的位置打开文件1.2 autogroup 命令学习1.2.1 augroup 基本语法 1.3 vim call 命令详细介绍 1.1 vim 如何从上次退出的位置打开文件 假设我打开了文件 test.c&#xff0c;然后我向下滚动到第 50 行&#xff0c;然后我做了一些修改并关闭了文件。…...

怎样学习C#上位机编程?

怎样学习C#上位机编程&#xff1f; 00001. 掌握C#编程和.NET框架基础。 00002. 学WinForm应用开发&#xff0c;了解控件使用和事件编程。 00003. 熟悉基本数据结构和算法&#xff0c;如链表、栈、队列。 00004. 理解串口通信协议和方法&#xff0c;用于与硬件交互。 00005…...

【算法-动态规划】两个字符串的删除操作-力扣 583

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…...

【06】基础知识:typescript中的泛型

一、泛型的定义 在软件开发中&#xff0c;我们不仅要创建一致的定义良好的API&#xff0c;同时也要考虑可重用性。 组件不仅能支持当前数据类型&#xff0c;同时也能支持未来的数据类型&#xff0c;这在创建大型系统时提供了十分灵活的功能。 在像 C# 和 Java 这样的语言中&…...

flutter 绘制原理探究

文章目录 Widget1、简介2、源码分析Element1、简介2、源码分析RenderObjectWidget 渲染过程总结思考Flutter 的核心设计思想便是“一切皆 Widget”,Widget 是 Flutter 功能的抽象描述,是视图的配置信息,同样也是数据的映射,是 Flutter 开发框架中最基本的概念。 在 Flutter…...

[Java]SPI扩展功能

一、什么是SPI Java SPI&#xff08;Service Provider Interface&#xff09;是Java官方提供的一种服务发现机制。 它允许在运行时动态地加载实现特定接口的类&#xff0c;而不需要在代码中显式地指定该类&#xff0c;从而实现解耦和灵活性。 二、实现原理 基于 Java 类加载…...

机器人命令表设计

演算命令 CLEAR 将数据 1 上被指定的编号以后的变数的内容&#xff0c;以及数据 2 上仅被指定的个数都清除至 0。 INC 在被指定的变数内容上加上 1。 DEC 在被指定的变数内容上减掉 1。 SET 在数据 1 上设定数据 2。 ADD 将数据 1 和数据 2 相加&#xff0c;得出的结果保存在数…...

STM32--WDG看门狗

文章目录 WDG简介IWDGIWDG的超时计算WWDGWWDG超时和窗口值设定独立看门狗工程WWDG工程 WDG简介 WDG看门狗&#xff08;Watchdog Timer&#xff09;是一种常见的硬件设备&#xff0c;在STM32F10系列中&#xff0c;有两种看门狗&#xff0c;分别是独立看门狗和窗口看门狗&#x…...

(※)力扣刷题-字符串-实现 strStr()(KMP算法)

28 实现 strStr() 实现 strStr() 函数。 给定一个 haystack 字符串和一个 needle 字符串&#xff0c;在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在&#xff0c;则返回 -1。 示例 1: 输入: haystack “hello”, needle “ll” 输出: 2 示例…...

Redis 集群 Redis 事务 Redis 流水线 Redis 发布订阅 Redis Lua脚本操作

Redis 集群 & Redis 事务 & Redis 流水线 & Redis 发布订阅 Redis 集群linux安装redis主从配置查看当前实例主从信息 Redis Sentinelsentinel Redis Cluster Redis 事务Redis 流水线Redis 发布订阅Redis Lua脚本操作 Redis 集群 linux安装redis 下载安装包&#…...

【算法与数据结构】--常见数据结构--栈和队列

一、栈 栈&#xff08;Stack&#xff09; 是一种基本的数据结构&#xff0c;具有后进先出&#xff08;LIFO&#xff09;的特性&#xff0c;类似于现实生活中的一叠盘子。栈用于存储一组元素&#xff0c;但只允许在栈顶进行插入&#xff08;入栈&#xff09;和删除&#xff08;…...

Linux shell编程学习笔记11:关系运算

Linux Shell 脚本编程和其他编程语言一样&#xff0c;支持算数、关系、布尔、字符串、文件测试等多种运算。前面几节我们研究了 Linux shell编程 中的 字符串运算 和 算术运算&#xff0c;今天我们来研究 Linux shell编程中的的关系运算。 一、关系运算符功能说明 运算符说明…...

JS标准库

学习一门编程语言不仅是掌握其语法。同等重要的是学习其标准库&#xff0c;从而熟练掌握语言本身提供的所有工具。 1 定型数组 js常规数组与C和Java等较低级语言的数组类型还是有很大区别。ES6新增了定型数组&#xff0c;与这些语言的低级数组非常接近。 定型数组严格来说并…...

Android 12.0 hal层添加自定义hal模块功能实现

1. 前言 在12.0的系统rom定制化开发中,在 对hal模块进行开发时,需要通过添加自定义的hal模块来实现某些功能时,就需要添加hal模块的相关功能,接下来就来实现一个案例来供参考 接下来就来具体实现这个功能 2.hal层添加自定义hal模块功能实现的核心类 hardware\interfaces…...

如何理解vue声明式渲染

Vue.js中的声明式渲染是一种用来描述用户界面的方式&#xff0c;它强调“声明”应该如何渲染页面&#xff0c;而不需要关心底层的DOM操作。这与传统的命令式渲染方式&#xff0c;即手动控制DOM元素的创建、更新和销毁&#xff0c;形成了鲜明的对比。 理解Vue的声明式渲染的关键…...

【已解决】Vue全局引入scss 个别页面不生效 / 不自动引入全局样式

项目里配置了全局样式的引入&#xff0c;今天新建了 demo 页面去修改 element 的样式&#xff0c;发现全局的样式没有引入进来。 问题原因 在此页面 没有任何样式导致的 项目在编译的时候&#xff0c;会把 .vue 文件的样式抽离到单独的 css 文件中。 当该页面没有css代码的时…...

MySQL之双主双从读写分离

一个主机 Master1 用于处理所有写请求&#xff0c;它的从机 Slave1 和另一台主机 Master2 还有它的从 机 Slave2 负责所有读请求。当 Master1 主机宕机后&#xff0c; Master2 主机负责写请求&#xff0c; Master1 、 Master2 互为备机。架构图如下 : 准备 我们…...

使用eBPF加速阿里云服务网格ASM

背景 随着云原生应用架构的快速发展&#xff0c;微服务架构已经成为了构建现代应用的主要方式之一。而在微服务架构中&#xff0c;服务间的通信变得至关重要。为了实现弹性和可伸缩性&#xff0c;许多组织开始采用服务网格技术来管理服务之间的通信。 Istio作为目前最受欢迎的…...

大型数据集处理之道:深入了解Hadoop及MapReduce原理

在大数据时代&#xff0c;处理海量数据是一项巨大挑战。而Hadoop作为一个开源的分布式计算框架&#xff0c;以其强大的处理能力和可靠性而备受推崇。本文将介绍Hadoop及MapReduce原理&#xff0c;帮助您全面了解大型数据集处理的核心技术。 Hadoop简介 Hadoop是一个基于Google…...

LCR 095. 最长公共子序列(C语言+动态规划)

1. 题目 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些字符&#xff08…...

程序员不写注释:探讨与反思

一、为什么程序员不写注释 当程序员选择不写注释时&#xff0c;通常有一系列常见原因&#xff0c;这些原因可以影响他们的决策和行为。同时&#xff0c;这个决策可能会带来多方面的影响和后果。以下是详细阐述为什么程序员不写注释的常见原因以及这种决策可能导致的影响和后果…...