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

[C++]类的继承

一、什么是继承

1.定义

        在 C++ 中,继承是一种机制,允许一个类(派生类)继承另一个类(基类)的成员(数据和函数)。继承使得派生类能够直接访问基类的公有和保护成员,同时也可以对这些成员进行扩展或修改。继承是一种“是一个”的关系,它允许一个类从另一个类继承其属性和方法,从而实现代码的复用。派生类是基类的一种特殊类型。

如何理解“是一个”?

如"狗是动物","猫是动物",Cat,Dog这两个类都继承了Animal这个类,它们是属于的关系,是“是一个”的关系。

2.继承的作用

        继承的主要作用是实现代码的复用:派生类可以重用基类的代码,而不需要重复编写相同的功能。同时,继承也允许派生类扩展或修改基类的行为。


二、基类与派生类

1.基类

        定义通用功能的类,供其他类继承。

2.派生类

        从基类继承的类,可以继承、扩展或修改基类的功能。

3.简单示例

        用一个简单的动物类和狗类示例,展示基类和派生类的关系。

#include <iostream>
using namespace std;// 基类:动物
class Animal {
public:void eat() { cout << "Animal is eating" << endl; }
};// 派生类:狗(继承了动物的功能)
class Dog : public Animal {
public:void bark() { cout << "Dog is barking" << endl; }
};int main() {Dog dog;dog.eat(); // 狗继承了动物的吃饭功能dog.bark(); // 狗有自己的叫的功能return 0;
}

三、继承的访问控制

1.公有继承

        当派生类以 public 方式继承基类时,基类的公有成员和保护成员在派生类中保持原有的访问权限,而私有成员完全不可访问。

1.公有成员(public):可以通过派生类对象访问。

2.保护成员(protected):可以在派生类内部访问,但不能通过派生类对象直接访问。

3.私有成员(private):完全无法访问。

4.示例:

#include <iostream>
using namespace std;class Animal {
public:void eat() { cout << "Animal eats." << endl; }  // 公有成员
protected:void sleep() { cout << "Animal sleeps." << endl; }  // 保护成员
private:void walk() { cout << "Animal walks." << endl; }  // 私有成员
};class Dog : public Animal {  // 公有继承
public:void dogActions() {eat();   // 可以访问公有成员sleep(); // 可以访问保护成员// walk(); // 错误,不能访问私有成员}
};int main() {Dog d;d.dogActions();return 0;
}
/*输出:
Animal eats.
Animal sleeps.
*/
1.解释:
  • 由于继承方式是 publicDog 类可以访问基类 Animal 的公有成员 eat() 和保护成员 sleep()
  • 但是,Dog 类不能访问基类 Animal 的私有成员 walk()

2.保护继承

        当派生类以 protected 方式继承基类时,基类的公有成员和保护成员都变成保护成员,只能在派生类及其子类中访问,不能通过派生类对象直接访问。

1.公有成员(public)变为保护成员(protected)。

2.保护成员(protected)仍然是保护成员。

3.私有成员(private)完全不可访问。

4.示例:

#include <iostream>
using namespace std;class Animal {
public:void eat() { cout << "Animal eats." << endl; }  // 公有成员
protected:void sleep() { cout << "Animal sleeps." << endl; }  // 保护成员
private:void walk() { cout << "Animal walks." << endl; }  // 私有成员
};class Dog : protected Animal {  // 保护继承
public:void dogActions() {eat();   // 可以访问保护成员sleep(); // 可以访问保护成员// walk(); // 错误,不能访问私有成员}
};int main() {Dog d;d.dogActions();// d.eat(); // 错误,不能通过对象访问 public 成员return 0;
}
/*输出:
Animal eats.
Animal sleeps.
*/
1.解释:
  • 由于继承方式是 protectedDog 类可以访问基类 Animal 的公有成员 eat() 和保护成员 sleep(),但是这些成员不能通过派生类对象直接访问。
  • Dog 类不能访问 Animal 类的私有成员 walk()

3.私有继承

        当派生类以 private 方式继承基类时,基类的公有成员和保护成员都变成私有成员,只能在派生类内部访问,不能通过派生类对象访问。

1.公有成员(public)变为私有成员(private)。

2.保护成员(protected)变为私有成员(private)。

3.私有成员(private)仍然不可访问。

4.示例:

#include <iostream>
using namespace std;class Animal {
public:void eat() { cout << "Animal eats." << endl; }  // 公有成员
protected:void sleep() { cout << "Animal sleeps." << endl; }  // 保护成员
private:void walk() { cout << "Animal walks." << endl; }  // 私有成员
};class Dog : private Animal {  // 私有继承
public:void dogActions() {eat();   // 可以访问私有成员(但只能在类内部访问)sleep(); // 可以访问保护成员(但只能在类内部访问)// walk(); // 错误,不能访问私有成员}
};int main() {Dog d;d.dogActions();//通过派生类的成员函数访问基类的成员函数// d.eat(); // 错误,不能通过对象访问 private 成员return 0;
}
/*输出:
Animal eats.
Animal sleeps.
*/
1.解释:
  • 由于继承方式是 privateDog 类可以访问基类 Animal 的公有成员 eat() 和保护成员 sleep(),但是这些成员都变成了 private,所以不能通过派生类对象直接访问。
  • 由于 eat()sleep()Dog 类的成员函数中被调用,它们可以访问 Animal 类的公有成员和保护成员。
  • 但是,如果尝试从 Dog 类的对象外部调用 eat()sleep()(如 d.eat()d.sleep()),就会报错,因为它们被转换成了私有或保护成员,不能通过外部代码直接访问。但因为Dog类的dogActions()方法是对外公开的,而这个dogActions()方法可以访问到基类的eat()和sleep()方法,因此可以通过Dog类的公有成员方法间接访问到基类的eat和sleep方法。
  • 类外Dog 类不能访问 Animal 类的私有成员 walk()

4. 总结继承的访问控制

继承方式基类 public 成员基类 protected 成员基类 private 成员
public保持 public保持 protected不能访问
protected变为 protected变为 protected不能访问
private变为 private变为 private不能访问

四、 抽象类与纯虚函数

  • 抽象类:一个不能直接实例化的类,通常包含纯虚函数。
  • 纯虚函数:没有实现的函数,要求派生类实现。
  • 示例:展示如何定义抽象类,并解释其在接口设计中的应用。
    class Animal {
    public:virtual void sound() = 0;  // 纯虚函数
    };class Dog : public Animal {
    public:void sound() override { std::cout << "Bark" << std::endl; }
    };
    

关于抽象类与纯虚函数我的这篇笔记里有详细讲,大家可以转站这里


五、多级继承与多重继承

1.多级继承

1. 定义

多级继承是指类的继承关系形成一个层次结构(是逐级进行的,类与类之间有明确的层级关系,每一层只能继承一个父类),其中派生类不仅继承了基类的成员,还继承了另外一个派生类的成员。

具体来说,就是:

  1. 基类(祖父类):最顶层的类。
  2. 派生类(父类):继承自基类的类。
  3. 子类(孙子类):继承自派生类(父类)的类。

在这种情况下,子类(孙子类)不仅继承了派生类(父类)的成员,还间接继承了基类(祖父类)的成员。子孙类的继承就叫多级继承。

例如:

#include<iostream>
using namespace std;class A {  // 基类
public:void showA() { cout << "Class A" << endl; }
};class B : public A {  // 派生类 B 继承自 A
public:void showB() { cout << "Class B" << endl; }
};class C : public B {  // 子类 C 继承自 B(间接继承自 A)
public:void showC() { cout << "Class C" << endl; }
};int main() {C obj;obj.showA();  // 通过 C 访问 A(通过继承的方式)obj.showB();  // 通过 C 访问 Bobj.showC();  // 通过 C 访问 Creturn 0;
}/*输出Class AClass BClass C
*/

在这个例子中:

  • A 是基类。
  • B 是派生类,它直接继承自 A
  • C 是子类,它继承自 B,但间接继承了 A 的成员。
  • C 类继承自 B 类,B 类又继承自 A 类。因此,C 类间接继承了 A 类的成员,这就是“继承链条中,派生类继续继承另一个派生类,形成一个层次结构”。
  • 子类(如 C)不仅可以访问直接继承的父类(如 B)的成员,还可以访问间接继承的祖父类(如 A)的成员。

2. 特性

  • 在多级继承中,继承链条从基类开始,一层一层向下继承。
  • 子类可以直接访问祖先类的公有成员,但需要注意继承的访问权限。例如,C 类可以通过继承链访问 A 类的公有成员。

3. 访问控制

  • 基类成员的访问控制(公有、保护、私有)会影响到继承链条中的派生类对基类成员的访问。
  • 在多级继承中,派生类不仅能访问自己类的成员,还能访问祖先类的公有成员和保护成员。

2.多重继承

1. 定义

多重继承是指一个类可以同时继承多个基类。也就是说,派生类可以同时继承多个父类的成员,具有多个基类。这是 C++ 允许的继承方式。例如:

class A {
public:void showA() { cout << "Class A" << endl; }
};class B {
public:void showB() { cout << "Class B" << endl; }
};class C : public A, public B {  // C 同时继承 A 和 B
public:void showC() { cout << "Class C" << endl; }
};

在这个例子中:

  • C 类继承了 A 类和 B 类,意味着 C 类将拥有 AB 类的成员。、

2. 特性

  • 派生类可以有多个直接的父类。
  • 每个父类的成员都可以被派生类访问。
  • 可能会发生命名冲突,如果多个父类有同名的成员,派生类需要通过作用域解析符来明确指定使用哪个父类的成员。
  • 如果两个基类有相同的成员,可能会出现钻石问题,但可以通过虚拟继承解决。

3. 访问控制

  • 和多级继承类似,多重继承中基类成员的访问控制(公有、保护、私有)依然适用。
  • 如果两个基类有同名的成员(钻石问题),在派生类中需要通过作用域解析符来区分它们。

4. 实例

#include <iostream>
using namespace std;class A {
public:void showA() { cout << "Class A" << endl; }
};class B {
public:void showB() { cout << "Class B" << endl; }
};class C : public A, public B {
public:void showC() { cout << "Class C" << endl; }
};int main() {C obj;obj.showA();  // 通过 C 访问 Aobj.showB();  // 通过 C 访问 Bobj.showC();  // 通过 C 访问 Creturn 0;
}
//输出:Class A Class B Class C

在这个例子中,C 类继承了 AB 两个类,所以它可以直接访问 AB 的公有成员。

5. 潜在的问题(如钻石问题)

多重继承可能导致一些潜在问题,最典型的就是 钻石问题。例如,如果两个基类有相同的成员,派生类可能无法明确继承哪个成员。C++ 通过 虚拟继承 来解决这个问题。

1.钻石问题的例子
#include <iostream>
using namespace std;class A {
public:void showA() { cout << "Class A" << endl; }
};class B : public A {
public:void showB() { cout << "Class B" << endl; }
};class C : public A {
public:void showC() { cout << "Class C" << endl; }
};class D : public B, public C {  // D 同时继承 B 和 C
public:void showD() { cout << "Class D" << endl; }
};int main() {D obj;obj.showA();  // 错误:不明确的继承(钻石问题)return 0;
}

在这个例子中,D 类继承了 BC,而 BC 都继承了 A 类。这样,D 类有两个 A 类的副本,因此不明确的继承会导致编译错误。

2.解决钻石问题:虚拟继承

通过使用虚拟继承(virtual 关键字),C++ 会确保基类 A 只有一个副本。

class A {
public:void showA() { cout << "Class A" << endl; }
};class B : virtual public A {
public:void showB() { cout << "Class B" << endl; }
};class C : virtual public A {
public:void showC() { cout << "Class C" << endl; }
};class D : public B, public C {
public:void showD() { cout << "Class D" << endl; }
};int main() {D obj;obj.showA();  // 现在可以访问 A,因为 A 只有一个副本return 0;
}
//输出:Class A

3.总结

1. 多级继承

  • 一种继承方式,子类继承父类,父类又继承祖父类,形成继承链条。
  • 子类能够访问基类和祖父类的成员(根据访问权限)。

2. 多重继承

  • 一个子类可以继承多个父类。
  • 如果多个父类有同名成员,可能会导致命名冲突(钻石问题),需要使用作用域解析符来明确调用。
  • 可以通过虚拟继承来避免钻石问题。
特性多级继承多重继承
继承关系逐级的,类与类之间形成一个明确的层级关系类同时继承多个父类,父类之间不一定有层级关系
父类数量每一层只有一个父类一个派生类可以有多个直接的父类
结构继承链是单向的,层次化的继承关系是并列的,可以有多个父类
命名冲突不容易发生命名冲突如果父类有相同成员,可能会发生命名冲突
例子class C : public B { ... }class B : public A { ... }class C : public A, public B { ... }

六、虚函数与多态

  • 虚函数:基类中的函数被声明为虚函数时,派生类可以重写该函数,实现运行时多态。
  • 多态:解释静态多态和动态多态的区别。
  • 示例:展示虚函数如何实现动态绑定,通过基类指针或引用调用派生类的函数。
    class Animal {
    public:virtual void sound() { std::cout << "Animal makes a sound" << std::endl; }
    };class Dog : public Animal {
    public:void sound() override { std::cout << "Dog barks" << std::endl; }
    };int main() {Animal* animal = new Dog();animal->sound();  // 动态绑定,调用 Dog 类中的 sound()delete animal;return 0;
    }
    

虚函数的详细笔记 

多态的详细笔记


七、继承中的构造函数与析构函数

1. 构造函数的继承行为

基本规则:
  • 派生类的构造函数会调用基类的构造函数。这意味着在派生类的构造函数中,基类的构造函数会先被调用,然后才会执行派生类的构造代码。
  • 基类的构造函数被自动调用,即使你没有显式调用它。默认情况下,如果基类有无参构造函数,那么它会在派生类构造函数中自动调用。
  • 如果基类有带参构造函数,派生类必须显式调用基类的构造函数(使用初始化列表)。
示例:构造函数继承行为
#include <iostream>
using namespace std;class Base {
public:Base() {  // 无参构造函数cout << "Base class constructor" << endl;}Base(int x) {  // 带参构造函数cout << "Base class constructor with value: " << x << endl;}
};class Derived : public Base {
public:Derived() : Base(10) {  // 显式调用基类的构造函数cout << "Derived class constructor" << endl;}
};int main() {Derived d;  // 创建派生类对象return 0;
}/*输出:
Base class constructor with value: 10
Derived class constructor*/

解释:

  • 当创建派生类对象 d 时,首先会调用基类 Base 的构造函数(带参构造函数 Base(int x)),并传入参数 10,然后才会执行派生类的构造函数。

2. 析构函数的继承行为

基本规则:
  • 派生类的析构函数会先执行。当对象销毁时,析构的顺序是:首先调用派生类的析构函数,然后再调用基类的析构函数。
  • 基类的析构函数应该是虚拟的:
    • 这是为了确保正确地析构派生类对象,避免资源泄漏。当你有一个基类和一个派生类,并且你通过基类指针去删除派生类对象时,如果基类的析构函数不是虚拟的,那么在删除对象时,程序就只会执行基类的析构函数派生类的析构函数就不会执行
    • 这种情况下,派生类对象在销毁时可能会留下未释放的资源(比如动态分配的内存、打开的文件或其他重要的资源),导致资源泄漏,即这些资源被占用但没有被正确释放。
    • 而如果基类的析构函数是虚拟的,程序就知道在删除派生类对象时,先执行派生类的析构函数,释放派生类分配的资源,然后再执行基类的析构函数,释放基类的资源。这样就能确保资源得到完全释放,避免浪费
示例:析构函数继承行为
#include <iostream>
using namespace std;class Base {
public:Base() {cout << "Base class constructor" << endl;}~Base() {  // 基类的析构函数cout << "Base class destructor" << endl;}
};class Derived : public Base {
public:Derived() {cout << "Derived class constructor" << endl;}~Derived() {  // 派生类的析构函数cout << "Derived class destructor" << endl;}
};int main() {Derived d;  // 创建派生类对象return 0;
}/*输出
Base class constructor
Derived class constructor
Derived class destructor
Base class destructor
*/

解释:

  • 创建对象 d 时,首先调用基类的构造函数,然后调用派生类的构造函数。
  • d 被销毁时,先调用派生类的析构函数,再调用基类的析构函数。
虚拟析构函数

在多态情况下,派生类对象是通过基类指针删除的,这时必须将基类的析构函数声明为虚拟的,以确保派生类的析构函数得到调用。否则,可能会导致资源泄漏。

#include <iostream>
using namespace std;class Base {
public:virtual ~Base() {  // 基类的虚拟析构函数cout << "Base class destructor" << endl;}
};class Derived : public Base {
public:~Derived() {  // 派生类的析构函数cout << "Derived class destructor" << endl;}
};int main() {Base* b = new Derived();  // 基类指针指向派生类对象delete b;  // 通过基类指针删除派生类对象return 0;
}/*
Derived class destructor
Base class destructor
*/

解释:

  • delete b 时,基类的虚拟析构函数确保先调用派生类的析构函数,然后再调用基类的析构函数。否则,如果基类的析构函数没有声明为虚拟的,就只会调用基类的析构函数,导致派生类的析构函数没有执行,可能造成资源泄漏。

八、继承与组合的比较

1.组合

1.定义:

组合是表示类之间**“有一个(has-a)”**关系的机制。它通过将一个类的对象作为另一个类的成员来实现功能复用。

2.特点:

  • 组合实现了类与类之间的松散耦合关系。
  • 被组合的对象可以是其他类的实例。

3.组合与继承的区别:

  • 继承:适用于表示 "是一个" 关系的情况。
  • 组合:适用于表示 "有一个" 关系的情况。类之间通过成员对象组合实现功能。

4.示例

#include <iostream>
using namespace std;class Leg {
public:void walk() {cout << "腿在跑。" << endl;}
};class Dog {
private:Leg leg;  // Dog 有一个 Leg
public:void walk() {leg.walk();  // 通过组合对象调用其功能}
};int main() {Dog dog;dog.walk(); // 调用组合对象的方法return 0;
}

2.继承 vs 组合:如何选择?

1.组合与继承的对比

方面继承组合
关系类型是一个(is-a)有一个(has-a)
耦合程度紧密耦合松散耦合
灵活性低(子类依赖父类)高(可以动态修改组合关系)
代码复用子类复用父类代码通过组合成员实现功能复用
使用场景表示类之间是一种“类型”的关系,如动物与狗表示类之间有一个成员的关系,如狗与腿

2. 综合示例

下面是继承和组合的综合使用示例,展示它们的区别和使用场景:

#include <iostream>
using namespace std;// 父类:动物
class Animal {
public:void eat() {cout << "Animal is eating." << endl;}
};// 组合类:腿
class Leg {
public:void walk() {cout << "Leg is walking." << endl;}
};// 子类:狗
class Dog : public Animal { // 继承:狗是动物
private:Leg leg; // 组合:狗有一个腿
public:void walk() {leg.walk(); // 使用组合对象的功能}void bark() {cout << "Dog barks!" << endl;}
};int main() {Dog dog;dog.eat();  // 继承自 Animaldog.walk(); // 组合的功能dog.bark(); // Dog 类的独特功能return 0;
}

3.最后:

  • 在设计复杂系统时,应尽量优先使用组合而非继承,因为组合更加灵活并且降低了类之间的耦合性。
  • 如果需要扩展父类的功能或表示一种“类型”的关系,则继承是合理的选择。

相关文章:

[C++]类的继承

一、什么是继承 1.定义&#xff1a; 在 C 中&#xff0c;继承是一种机制&#xff0c;允许一个类&#xff08;派生类&#xff09;继承另一个类&#xff08;基类&#xff09;的成员&#xff08;数据和函数&#xff09;。继承使得派生类能够直接访问基类的公有和保护成员&#xf…...

2024安装hexo和next并部署到github和服务器最新教程

碎碎念 本来打算写点算法题上文所说的题目&#xff0c;结果被其他事情吸引了注意力。其实我之前也有过其他博客网站&#xff0c;但因为长期不维护&#xff0c;导致数据丢失其实是我懒得备份。这个博客现在部署在GitHub Pages上&#xff0c;github不倒&#xff0c;网站不灭&…...

【spring】@Qualifier注解

目录 1. 说明2. 用法示例2.1 标注在字段上2.2 标注在方法上2.3 标注在类上2.4 在自定义注解上的应用 3. 注意事项 1. 说明 1.Qualifier是Spring框架中的一个注解&#xff0c;主要用于解决依赖注入时的歧义性问题。2.定义&#xff1a;Qualifier是一个限定符注解&#xff0c;用于…...

uniapp 应用的生命周期、页面的生命周期、组件的生命周期

uniapp 作为一款跨平台的移动应用开发框架&#xff0c;其生命周期分为应用生命周期、页面生命周期和组件生命周期。下面分别介绍这三种生命周期的具体内容&#xff1a; 应用生命周期 应用生命周期仅适用于整个应用&#xff0c;在 App.vue 中可以监听到以下生命周期函数&#…...

热更新解决方案4——xLua热补丁

概述 运行时不在执行C#中的代码&#xff0c;而是执行Lua中的代码&#xff0c;相当于是打了个补丁。 1.第一个热补丁 2.多函数替换 3.协程函数替换 在原HotfixMain脚本中只加个协程函数即可&#xff08;和在Start中启动协程函数&#xff09; 4.索引器和属性替换 在HotfixMain中…...

【MARL】深入理解多智能体近端策略优化(MAPPO)算法与调参

&#x1f4e2;本篇文章是博主强化学习&#xff08;RL&#xff09;领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对相关等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅…...

3.2.1.2 汇编版 原子操作 CAS

基本原理说明 在 x86 和 ARM 架构上&#xff0c;原子操作通常利用硬件提供的原子指令来实现&#xff0c;比如 LOCK 前缀&#xff08;x86&#xff09;或 LDREX/STREX&#xff08;ARM&#xff09;。以下是一些关键的原子操作&#xff08;例如原子递增和比较交换&#xff09;的汇…...

关于llama2:从原始llama-2-7b到llama-2-7b-hf的权重转换教程

1.首先&#xff0c;我是从各个教程里面选了一个实际操作的教程&#xff08;这样更加靠谱&#xff09;&#xff1a;下载llama2-7b并转hf模型_huggingface 下载llama2-7b-chat-hf-CSDN博客 2.但是&#xff0c;其实我在另外一篇更好的教程里面看到过一个坑&#xff08;这篇好像是腾…...

物理机内网穿透

前言&#xff1a; 本文主要讲述如何使用内网穿透以及其安全性。 将带领大家在公网上搭建几个常用靶场。 一&#xff0c;什么是内网穿透。 大多数情况下&#xff0c;我们的个人电脑都处于内网&#xff0c;即没有可公开访问的独立 IP 地址&#xff0c;因此其他内网用户找不到…...

构建一个rust生产应用读书笔记四(实战1)

我们需要从访客那里收集哪些信息&#xff0c;以便将其登记为电子邮件通讯的订阅者&#xff1f; 电子邮件地址&#xff1a;这是最基本的要求&#xff0c;因为我们需要通过电子邮件地址向订阅者发送内容。姓名&#xff1a;虽然这不是强制性的&#xff0c;但我们希望收集一个名字…...

[LeetCode-Python版]206. 反转链表(迭代+递归两种解法)

题目 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1] 示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1] 示例 3&#xff1…...

shardingsphere分库分表跨库访问 添加分片规则

shardingsphere分库分表跨库访问 添加分片规则 建立 JDBC 环境 创建表 t_order&#xff1a; CREATE TABLE t_order (tid bigint(20) NOT NULL,tname varchar(255) DEFAULT NULL,goods_id bigint(20) DEFAULT NULL,tstatus varchar(255) DEFAULT NULL,PRIMARY KEY (tid) ) E…...

【NLP 15、深度学习处理文本】

目录 一、反向传播 ​编辑 1.反向传播运算过程 2.前向传播和反向传播的作用 前向传播 反向传播 3.定义模型&#xff08;torch包&#xff09; 4.手动实现 ① 线性层 ② sigmoid激活函数 ③ 手动实现MSE均方差损失函数 ④ 前向传播 ⑤ 手动实现梯度计算 ⑤ 权重的更新&#xff1a…...

Android Studio创建新项目并引入第三方so外部aar库驱动NFC读写器读写IC卡

本示例使用设备&#xff1a;https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.52de2c1bbW3AUC&ftt&id615391857885 一、打开Android Studio,点击 File> New>New project 菜单&#xff0c;选择 要创建的项目模版&#xff0c;点击 Next 二、输入项目名称…...

3D视觉[一]3D计算机视觉

3D视觉[一]3D计算机视觉 3D计算机视觉概述 像机标定 文章目录 3D视觉[一]3D计算机视觉前言一、人类视觉二、计算机视觉2.1 计算机视觉的研究目的2.2 计算机视觉的研究任务2.3 计算机视觉的研究方法2.4 视觉计算理论2.5 马尔框架中计算机视觉表达的四个层次2.5.1 图像&#xff…...

Linux权限(超详细彻底搞懂Linux的权限)

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;Linux &#x1f339;往期回顾&#x1f339;&#xff1a;Linux常见指令(初学者必看) &#x1f516;流水不争&#xff0c;争的是滔滔不 一、Linux下的两种用户超级用户&…...

Ubuntu22.04安装docker desktop遇到的bug

1. 确认已启用 KVM 虚拟化 如果加载了模块&#xff0c;输出应该如下图。说明 Intel CPU 的 KVM 模块已开启。 否则在VMware开启宿主机虚拟化功能&#xff1a; 2. 下一步操作&#xff1a; Ubuntu | Docker Docs 3. 启动Docker桌面后发现账户登陆不上去&#xff1a; Sign in | …...

网新恒天八股总结

Java的基本数据类型 四类八种 整数类型&#xff1a;byte,short,int,long 浮点类型&#xff1a;float,double 字符类型&#xff1a;char 布尔类型&#xff1a;boolean char类型的范围 0 ~ 65535&#xff0c;可以表示16位无符号整数 equals和的区别 &&#xff0c;&&a…...

【AIGC】与模型对话:理解与预防ChatGPT中的常见误解

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;模型的工作原理和用户期望差异人工智能模型的基本工作原理认知上的局限与误解用户期望与模型实际能力的差距精确理解用户意图的重要性实际应用中的建议 &…...

09篇--图片的水印添加(掩膜的运用)

如何添加水印&#xff1f; 添加水印其实可以理解为将一张图片中的某个物体或者图案提取出来&#xff0c;然后叠加到另一张图片上。具体的操作思想是通过将原始图片转换成灰度图&#xff0c;并进行二值化处理&#xff0c;去除背景部分&#xff0c;得到一个类似掩膜的图像。然后…...

Qt 使用modbus协议

Qt 框架下 使用modbus协议 一&#xff0c;使用Qt原生的 QModbusClient &#xff0c;比如QModbusTcpClient 1&#xff0c;因为modbus的读写 需要在同一个线程中&#xff0c;所以需要在主线程中利用moveToThread的方式&#xff0c;将业务逻辑封装到 子线程中。 2&#xff0c;m…...

pip离线安装一个github仓库

要使用pip安装一个本地Git仓库&#xff0c;你可以按照以下步骤操作&#xff1a; 确保你已经克隆了Git仓库到本地。 进入仓库所在的目录。 使用pip安装。 以下是具体的命令&#xff1a; 克隆Git仓库到本地&#xff08;替换下面的URL为你的仓库URL&#xff09; git clone https…...

【ETCD】【源码阅读】深入分析 storeTxnWrite.Put方法源码

该方法是 storeTxnWrite 类型中的核心方法&#xff0c;负责将键值对存储到数据库&#xff0c;同时处理键的元数据&#xff08;如版本、修订号、租约&#xff09;并管理租约关联。 目录 一、完整代码二、方法详解方法签名1. 计算修订号并初始化变量2. 检查键是否已存在3. 生成索…...

桥接模式的理解和实践

桥接模式&#xff08;Bridge Pattern&#xff09;&#xff0c;又称桥梁模式&#xff0c;是一种结构型设计模式。它的核心思想是将抽象部分与实现部分分离&#xff0c;使它们可以独立地进行变化&#xff0c;从而提高系统的灵活性和可扩展性。本文将详细介绍桥接模式的概念、原理…...

【Rust自学】3.2. 数据类型:标量类型

3.2.0. 写在正文之前 欢迎来到Rust自学的第三章&#xff0c;一共有6个小节&#xff0c;分别是: 变量与可变性数据类型&#xff1a;标量类型&#xff08;本文&#xff09;数据类型&#xff1a;复合类型函数和注释控制流&#xff1a;if else控制流&#xff1a;循环 通过第二章…...

【Leetcode Top 100】199. 二叉树的右视图

问题背景 给定一个二叉树的 根节点 r o o t root root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 数据约束 二叉树的节点个数的范围是 [ 0 , 100 ] [0,100] [0,100] − 100 ≤ N o d e . v a l ≤ 100…...

Java并发编程框架之其他并发工具

选错了就选错了&#xff0c;不要一遍一遍的后悔&#xff0c;总是一遍遍的想&#xff0c;当时怎么样就好了&#xff0c;不要欺负当时的自己&#xff0c;当时你一个人站在迷雾中&#xff0c;也很迷茫&#xff0c;就算重新来一遍&#xff0c;以你当时的阅历和心智&#xff0c;还是…...

MinerU:PDF文档提取工具

目录 docker一键启动本地配置下载模型权重文件demo.py使用命令行启动GPU使用情况 wget https://github.com/opendatalab/MinerU/raw/master/Dockerfile docker build -t mineru:latest .docker一键启动 有点问题&#xff0c;晚点更新 本地配置 就是在Python环境中配置依赖和…...

Unity性能优化---使用SpriteAtlas创建图集进行批次优化

在日常游戏开发中&#xff0c;UI是不可缺少的模块&#xff0c;而在UI中又使用着大量的图片&#xff0c;特别是2D游戏还有很多精灵图片存在&#xff0c;如果不加以处理&#xff0c;会导致很高的Batches&#xff0c;影响性能。 比如如下的例子&#xff1a; Batches是9&#xff0…...

wazuh-modules-sca-scan

sca模块主函数wm_sca_main -> wm_sca_start 检查policy文件中的每一个项目wm_sca_check_policy static int wm_sca_check_policy(const cJSON * const policy, const cJSON * const checks, OSHash *global_check_list) {if(!policy) {return 1;}const cJSON * const id c…...

力扣-图论-15【算法学习day.65】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非…...

JS萤石云录像回放拖动进度条无法正常播放

问题描述&#xff1a; 本项目版本&#xff1a;vue2.6.12&#xff0c;webpack3.6.0&#xff0c;ezuikit-js0.7.2 在使用萤石云的JavaScript SDK做监控的直播、录像回放时&#xff0c;遇到部分设备的录像回放&#xff0c;无法根据控制面板的拖动进度条查看某时间段的录像。 官方…...

Spring Boot 启动时间优化全攻略

引言 随着 Spring Boot 的广泛应用&#xff0c;开发者享受到了快速开发和自动化配置的便利。然而&#xff0c;随着项目复杂度的增加&#xff0c;Spring Boot 项目启动时间也变得越来越长&#xff0c;这在开发、调试和部署阶段可能会成为效率瓶颈。如何优化 Spring Boot 的启动…...

ubuntu服务器木马类挖矿程序排查、及安全管理总结

版本 24.04 由于GPU多卡服务器多人使用&#xff0c;需要链接隧道ssh等&#xff0c;容易中招挖矿脚本。 总的思路是&#xff0c;顺着进程的PID回溯最终的程序运行起点&#xff0c;这里可以先看一下日志&#xff1a; journalctl -u PID 通过 PID 精确定位进程的信息&#xff0c…...

redis 使用Lettuce 当redis挂掉重启之后 网络是怎么重新连接

Lettuce是一个高性能的Java Redis客户端&#xff0c;支持同步、异步和反应式编程模式 Lettuce的核心功能包括&#xff1a; ‌高性能‌&#xff1a;通过使用Netty作为底层网络通信框架&#xff0c;实现了非阻塞IO&#xff0c;提高了性能。‌丰富的API‌&#xff1a;提供了丰富…...

【PyTorch】实现在训练过程中自定义动态调整学习率

问题描述&#xff1a; 在使用 PyTorch 训练自定义神经网络时&#xff0c;我们希望能够动态地调整学习率&#xff0c;以便在训练过程中逐渐优化模型&#xff0c;避免过拟合并加速收敛。那么&#xff0c;如何在 PyTorch 中实现这一功能呢&#xff1f; 解决方案&#xff1a; 在训…...

【Flink-scala】DataStream编程模型总结

系列文章目录 1.【Flink-Scala】DataStream编程模型之数据源、数据转换、数据输出 2.【Flink-scala】DataStream编程模型之 窗口的划分-时间概念-窗口计算程序 3.【Flink-scala】DataStream编程模型之窗口计算-触发器-驱逐器 4.【Flink-scala】DataStream编程模型之水位线 5.【…...

语音芯片赋能可穿戴设备:开启个性化音频新体验

在科技日新月异的今天&#xff0c;语音芯片与可穿戴设备的携手合作&#xff0c;正引领我们步入一个前所未有的个性化音频时代。这一创新融合&#xff0c;用户可以享受到更加个性化、沉浸式的音频体验。下面将详细介绍语音芯片与可穿戴设备合作的优点和具体应用。 1. 定制化音效…...

JavaFX使用jfoenix的UI控件

jfoenix还是一个不错的样式&#xff0c;推荐使用&#xff0c;而且也可以支持scene builder中的拖拖拽拽 需要注意的是过高的javafx版本可能会使得某些样式或控件无法使用 比如alert控件&#xff0c;亲测javaFX 19版本可以正常使用 1.在pom.xml中引入依赖 GitHub地址https://gi…...

SpringBoot集成ENC对配置文件进行加密

在线MD5生成工具 配置文件加密&#xff0c;集成ENC 引入POM依赖 <!-- ENC配置文件加密 --><dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>2.1.2</ver…...

基于AI对话生成剧情AVG游戏

游戏开发这个领域&#xff0c;一直有较高的学习门槛。作为一个非专业的游戏爱好者&#xff0c;如果想要开发游戏&#xff0c;往往受制于游戏引擎的专业程度&#xff0c;难以完成复杂的游戏项目。 AI IDE的诞生&#xff0c;提供了另外的一种思路&#xff0c;即通过AI 生成项目及…...

MAVEN--Maven的生命周期,pom.xml详解,Maven的高级特性(模块化、聚合、依赖管理)

目录 &#xff08;一&#xff09;Maven的生命周期 1.Maven的三套生命周期 2.Maven常用命令 &#xff08;二&#xff09;pom.xml详解 &#xff08;三&#xff09;Maven的高级特性&#xff08;模块化、聚合、依赖管理&#xff09; 1.Maven的依赖范围 2.版本维护 3.依赖传…...

SpringBoot的事务钩子函数

如果需要在A方法执行完成之后做一个不影响主方法运行的动作B&#xff0c;我们需要判断这个A方法是否存在事务&#xff0c;并且使用异步执行动作B&#xff1b; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transa…...

uniapp滚动消息列表

两个相同的循环列表&#xff0c;循环滚动 <view class"winners_list uni-flex uni-column" :animation"animationData"><view v-for"(item, index) in winnersList" :key"index" class"li uni-flex uni-column"&g…...

基于python对pdf文件进行加密等操作

利用python对pdf文件进行操作 读取pdf-源码 import PyPDF2 # 读取pdf格式的文件 reader PyPDF2.PdfFileReader(示例文件/aaa.pdf) print(reader)# 读取指定页面的文件 page reader.getPage(0) # 输出当前页面的文本数据 print(page.extractText())读取pdf-源码解析 这段代…...

Three.js材质纹理扩散过渡

Three.js材质纹理扩散过渡 import * as THREE from "three"; import { ThreeHelper } from "/src/ThreeHelper"; import { LoadGLTF, MethodBaseSceneSet } from "/src/ThreeHelper/decorators"; import { MainScreen } from "/src/compone…...

【Leetcode 每日一题 - 扩展】45. 跳跃游戏 II

问题背景 给定一个长度为 n n n 的 0 0 0 索引 整数数组 n u m s nums nums。初始位置为 n u m s [ 0 ] nums[0] nums[0]。 每个元素 n u m s [ i ] nums[i] nums[i] 表示从索引 i i i 向前跳转的最大长度。换句话说&#xff0c;如果你在 n u m s [ i ] nums[i] nums[i…...

被裁20240927 --- YOLO 算法

背景 在云端部署ViSP&#xff0c;ViSP实现视觉伺服、yolo实现视觉跟踪。 开源的2d视觉跟踪算法有哪些&#xff1f; 开源的2D视觉跟踪算法有很多呢&#xff0c;这里给你推荐一些比较知名和常用的吧。 ByteTrackV2&#xff1a;这是一个通用2D跟踪算法&#xff0c;提出了分层的…...

AI技术架构:从基础设施到应用

人工智能&#xff08;AI&#xff09;的发展&#xff0c;正以前所未有的速度重塑我们的世界。了解AI技术架构&#xff0c;不仅能帮助我们看懂 AI 的底层逻辑&#xff0c;还能掌握其对各行业变革的潜力与方向。 一、基础设施层&#xff1a;AI 技术的坚实地基 基础设施层是 AI 技…...

植物大战僵尸辅助【控制台版本】

前面介绍了使用CE和OD的简单使用&#xff1a;CE和OD介绍和使用CE查找阳光的教学&#xff1a;阳光基地址和偏移地址&#xff0c;下面先使用最简单的控制台程序来实现修改阳光的功能。 项目地址 1.分析程序 我们的控制台程序想要修改植物大战僵尸游戏内的数据&#xff0c;它们…...