1. 必须实现拷贝构造函数的场景

核心问题:默认拷贝构造的缺陷

C++ 默认的拷贝构造函数(浅拷贝),会直接拷贝指针 / 引用成员的地址。若类包含引用成员指向堆内存的指针,浅拷贝会导致 “多个对象共享同一份资源”,引发 double free、数据混乱等问题。此时必须手动实现深拷贝的拷贝构造函数。

场景 1:类包含引用成员(int&

引用成员必须绑定有效对象,默认拷贝构造会让新对象的引用绑定到原对象的引用成员(共享同一块内存)。若原对象的引用成员失效(如局部变量销毁),新对象的引用会变成 “野引用”。

示例:默认拷贝构造的危险

class Test {
public:int& ref;// 构造函数:绑定引用到外部变量Test(int& r) : ref(r) {} // 默认拷贝构造(编译器生成,危险!)// Test(const Test& other) : ref(other.ref) {} 
};int main() {int x = 10;Test t1(x); // 用默认拷贝构造,t2.ref 也绑定到 xTest t2 = t1; x = 20;// t1.ref 和 t2.ref 都变成20(共享x)cout << t1.ref << " " << t2.ref << endl; // 若 x 是局部变量,t2 的引用可能失效// int y = 30;// Test t3(y);// Test t4 = t3;// y 销毁后,t4.ref 变成野引用return 0;
}

解决方案:手动实现拷贝构造
需让新对象的引用绑定到新的有效变量(或确保原引用的生命周期足够长)。若引用需绑定到独立变量,需重新构造引用关系(如示例中让新对象的引用绑定到原引用的值,而非原引用本身)。

class Test {
public:int& ref;Test(int& r) : ref(r) {} // 手动实现拷贝构造:让新对象的引用绑定到原引用的值Test(const Test& other) // 用原引用的值,构造新的 int 变量,再绑定引用: ref(*new int(other.ref)) {} // 注意:需手动管理内存,否则内存泄漏~Test() { // 释放 new 出来的 int(否则内存泄漏)delete &ref; }
};
场景 2:类包含指针成员(指向堆内存)

默认拷贝构造会拷贝指针地址(浅拷贝),导致多个对象共享堆内存。若一个对象释放内存,其他对象的指针会变成 “野指针”。

示例:浅拷贝导致 double free

class Test {
public:int* ptr;Test(int val) : ptr(new int(val)) {} // 默认拷贝构造(浅拷贝,危险!)// Test(const Test& other) : ptr(other.ptr) {} ~Test() { delete ptr; }
};int main() {Test t1(10);// 浅拷贝,t2.ptr 和 t1.ptr 指向同一块内存Test t2 = t1; // t1 析构时释放 ptr,t2.ptr 变成野指针// t2 析构时再次释放,引发 double freereturn 0;
}

解决方案:深拷贝的拷贝构造

class Test {
public:int* ptr;Test(int val) : ptr(new int(val)) {} // 深拷贝:新对象重新分配堆内存Test(const Test& other) : ptr(new int(*other.ptr)) {} ~Test() { delete ptr; }
};
总结:必须实现拷贝构造的时机

当类包含 ** 引用成员(需重新绑定)指针成员(需深拷贝)** 时,默认浅拷贝会引发未定义行为,必须手动实现拷贝构造函数,确保:

  • 引用成员绑定到新的有效对象(或值)。
  • 指针成员重新分配堆内存(深拷贝)。

2. 对 explicit 关键字的理解

核心作用:禁止单参数构造函数的隐式类型转换

C++ 中,单参数构造函数(或多参数但其余参数有默认值的构造函数)会被编译器用作隐式类型转换:用一个类型的值(如int)直接构造另一个类型的对象(如MyInt)。explicit 关键字禁止这种隐式转换,强制要求显式构造对象。

场景 1:单参数构造函数的隐式转换(危险!)
class MyInt {
public:int value;// 单参数构造函数:int → MyIntMyInt(int num) : value(num) {} 
};void print(MyInt mi) {cout << mi.value << endl;
}int main() {// 隐式转换:10 → MyInt(10)print(10); return 0;
}

这种隐式转换可能让代码逻辑晦涩(读者难以发现类型转换),甚至引发错误(如意外触发构造函数的副作用)。

场景 2:explicit 禁止隐式转换

给构造函数加 explicit 后,编译器不再允许隐式转换,必须显式构造对象。

class MyInt {
public:int value;// 禁止隐式转换explicit MyInt(int num) : value(num) {} 
};void print(MyInt mi) {cout << mi.value << endl;
}int main() {// 编译报错:无法隐式转换 int→MyInt// print(10); // 必须显式构造print(MyInt(10)); return 0;
}
扩展:C++11 后支持多参数的 explicit(配合列表初始化)

C++11 允许 explicit 修饰多参数构造函数(需配合{}列表初始化),禁止用括号初始化的隐式转换。

class Point {
public:int x, y;// 多参数构造函数,explicit 禁止隐式转换explicit Point(int a, int b) : x(a), y(b) {} 
};void draw(Point p) { /*...*/ }int main() {// 编译报错:无法隐式转换 (1,2)→Point// draw((1,2)); // 必须显式构造draw(Point(1,2)); // 或用列表初始化(C++11)draw({1,2}); return 0;
}
最佳实践
  • 所有单参数构造函数(或可能被隐式转换的构造函数)都应加 explicit,避免意外的隐式转换。
  • 仅在需要隐式转换的场景(如智能指针std::shared_ptr的构造),才不用 explicit

3. 无法被继承的函数

核心规则:构造函数、析构函数、赋值运算符、final 修饰的函数无法被继承
函数类型无法继承的原因
构造函数构造函数与类的初始化逻辑强绑定,子类需独立构造
析构函数析构函数与类的资源释放逻辑强绑定,子类需独立析构
赋值运算符(operator=赋值需处理子类新增成员,继承父类的赋值逻辑会遗漏子类成员
被 final 修饰的虚函数final 显式禁止子类重写该虚函数
详细解析
(1)构造函数与析构函数
  • 构造函数:子类对象包含父类成员和子类成员,父类构造函数负责初始化父类成员,子类构造函数需调用父类构造函数(通过初始化列表),无法直接继承父类构造逻辑(否则无法初始化子类新增成员)。
  • 析构函数:子类析构函数需先释放子类资源,再调用父类析构函数。若继承父类析构函数,无法保证子类资源优先释放,可能导致内存泄漏。
(2)赋值运算符(operator=

父类的 operator= 仅处理父类成员,子类的 operator= 需处理子类新增成员。若继承父类的 operator=,会导致子类成员未被赋值(遗漏),引发数据不完整。

示例:继承赋值运算符的危险

class Father {
public:int x;Father& operator=(const Father& other) {x = other.x;return *this;}
};class Son : public Father {
public:int y;// 若继承父类 operator=,会遗漏 y 的赋值Son& operator=(const Son& other) {// 必须手动调用父类的 operator=Father::operator=(other); y = other.y;return *this;}
};
(3)被 final 修饰的虚函数

final 是 C++11 引入的关键字,用于禁止虚函数被重写。若父类虚函数被 final 修饰,子类无法继承(重写)该函数,否则编译报错。

class Father {
public:// 禁止子类重写virtual void func() final { /*...*/ } 
};class Son : public Father {
public:// 编译报错:无法重写 final 函数// void func() override { /*...*/ } 
};

4. 继承中同名成员的处理

核心规则:子类同名成员会隐藏父类同名成员(而非覆盖),需用作用域运算符 :: 显式访问父类成员。
场景 1:子类定义与父类同名的成员变量

父类的同名成员变量仍被继承到子类,但子类的同名成员会 “隐藏” 父类成员(默认访问子类成员)。

class Father {
public:int money = 100; 
};class Son : public Father {
public:// 子类同名成员,隐藏父类的 moneyint money = 50; 
};int main() {Son son;// 访问子类的 money(输出50)cout << son.money << endl; // 显式访问父类的 money(输出100)cout << son.Father::money << endl; return 0;
}
场景 2:子类定义与父类同名的成员函数

若子类函数与父类函数同名但参数不同(非虚函数),会隐藏父类的所有同名函数(无论参数是否相同)。若子类函数与父类函数同名且参数相同(虚函数),则重写父类函数(多态)。

示例:同名非虚函数的隐藏

class Father {
public:void func(int x) { cout << "Father: " << x << endl; }
};class Son : public Father {
public:// 同名但参数不同,隐藏父类的 func(int)void func(double x) { cout << "Son: " << x << endl; }
};int main() {Son son;// 调用子类的 func(double)son.func(3.14); // 编译报错:父类的 func(int) 被隐藏// son.func(10); // 显式访问父类的 func(int)son.Father::func(10); return 0;
}
最佳实践
  • 避免同名成员:设计类时,尽量让子类成员与父类成员名称不同,减少混淆。
  • 显式访问父类成员:若必须同名,用 Father::moneyFather::func() 明确访问父类成员,增强代码可读性。

5. 继承中构造与析构的顺序

构造顺序:父类 → 成员对象 → 子类

对象构造时,需先确保父类和成员对象的构造完成(为子类提供初始化的基础),因此顺序为:

  1. 调用父类的构造函数(按继承顺序,从最顶层父类到直接父类)。
  2. 调用成员对象的构造函数(按成员在子类中的声明顺序)。
  3. 调用子类的构造函数体
示例:多层继承 + 成员对象的构造顺序
class GrandFather {
public:GrandFather() { cout << "GrandFather 构造" << endl; }
};class Father : public GrandFather {
public:Father() { cout << "Father 构造" << endl; }
};class Member {
public:Member() { cout << "Member 构造" << endl; }
};class Son : public Father {
public:Member m;Son() { cout << "Son 构造" << endl; }
};int main() {Son son;// 输出顺序:// GrandFather 构造 → Father 构造 → Member 构造 → Son 构造return 0;
}
析构顺序:子类 → 成员对象 → 父类

对象析构时,需先释放子类资源,再释放成员对象和父类资源(避免父类资源先释放,子类资源访问无效内存),因此顺序与构造相反:

  1. 调用子类的析构函数体
  2. 调用成员对象的析构函数(按构造顺序的逆序)。
  3. 调用父类的析构函数(按继承顺序的逆序,从直接父类到最顶层父类)。
示例:析构顺序验证
class GrandFather {
public:~GrandFather() { cout << "GrandFather 析构" << endl; }
};class Father : public GrandFather {
public:~Father() { cout << "Father 析构" << endl; }
};class Member {
public:~Member() { cout << "Member 析构" << endl; }
};class Son : public Father {
public:Member m;~Son() { cout << "Son 析构" << endl; }
};int main() {Son son;// 构造顺序:GrandFather → Father → Member → Son// 析构顺序:Son → Member → Father → GrandFatherreturn 0;
}

6. 继承中的构造与析构顺序

继承体系中,构造函数和析构函数的调用顺序严格遵循 “先构造父类,再构造子类;先析构子类,再析构父类” 的规则,这是由 C++ 对象的内存布局和生命周期决定的。

一、构造函数的调用顺序
1. 子类对象创建时,先调用父类构造函数

原理
子类继承了父类的成员变量,这些成员的初始化依赖父类的构造逻辑。如果先构造子类,父类成员可能因未初始化而出现访问非法内存、数据未定义等问题。因此,C++ 强制规定:创建子类对象时,必须先确保父类构造完成,为继承的成员打好初始化基础。

示例验证

class Father {
public:Father() {cout << "Father 构造函数调用" << endl;}
};class Son : public Father {
public:Son() {cout << "Son 构造函数调用" << endl;}
};int main() {Son son; // 输出顺序:// Father 构造函数调用 → Son 构造函数调用return 0;
}

内存视角
子类对象的内存布局中,父类成员在前、子类成员在后。构造时必须先初始化父类部分(确保父类成员有效),再初始化子类独有的成员。

2. 父类有参数时,子类必须用初始化列表显式调用

场景
如果父类没有默认构造函数(即构造函数需要传入参数,无法无参调用),子类构造函数必须在初始化列表显式调用父类的有参构造函数,否则编译器报错(因为父类无法自动用默认构造初始化)。

示例验证

class Father {
public:int money;// 父类没有默认构造,必须传参初始化Father(int m) : money(m) {cout << "Father 带参构造:" << money << endl;}
};class Son : public Father {
public:int toyNum;// 子类构造函数初始化列表,显式调用父类带参构造Son(int m, int toy) // 调用父类有参构造,初始化父类成员 money: Father(m),  // 初始化子类成员 toyNumtoyNum(toy)  {cout << "Son 带参构造:" << toyNum << endl;}
};int main() {Son son(100, 5); // 输出顺序:// Father 带参构造:100 → Son 带参构造:5return 0;
}

关键细节

  • 初始化列表的调用顺序不受书写顺序影响,而是严格按照成员变量在类中声明的顺序执行。
  • 若父类无默认构造,子类构造函数的初始化列表必须显式调用父类有参构造,否则编译报错(编译器无法自动推断父类的构造方式)。
二、析构函数的调用顺序

原理
对象销毁时,要保证 “先构造的后销毁,后构造的先销毁”。子类对象依赖父类的资源(如父类成员变量、父类申请的堆内存),若父类先销毁,子类在析构时可能访问已销毁的父类成员,引发未定义行为。因此,析构顺序严格与构造顺序相反:先调子类析构函数,再调父类析构函数

示例验证

class Father {
public:~Father() {cout << "Father 析构函数调用" << endl;}
};class Son : public Father {
public:~Son() {cout << "Son 析构函数调用" << endl;}
};int main() {Son son; // 构造顺序:Father → Son// 析构顺序:Son → Father// 输出:// Son 析构函数调用 → Father 析构函数调用return 0;
}

内存视角
子类析构时,需先释放子类独有的资源(避免父类析构后,子类资源释放逻辑依赖父类成员但父类已销毁),再通知父类释放其资源。

7. 子类调用成员对象、父类有参构造的注意点

子类构造函数不仅要处理父类的构造,还要处理 ** 成员对象(子类中包含的其他类对象)** 的构造。成员对象的构造顺序与父类构造紧密相关,需特别注意默认构造和有参构造的调用规则。

一、默认构造的自动调用

规则
当父类和成员对象存在默认构造函数(无参构造函数,或所有参数都有默认值的构造函数)时,子类构造时会自动调用它们的默认构造,无需手动在初始化列表中处理。

示例验证

class Father {
public:// 父类默认构造(无参)Father() { cout << "Father 默认构造" << endl; }
};class Member {
public:// 成员对象默认构造(无参)Member() { cout << "Member 默认构造" << endl; }
};class Son : public Father {
private:// 子类包含的成员对象Member m; 
public:Son() { cout << "Son 构造" << endl; }
};int main() {Son son; // 输出顺序:// Father 默认构造 → Member 默认构造 → Son 构造return 0;
}

原理
编译器会自动在子类构造函数的初始化列表中,插入对父类默认构造和成员对象默认构造的调用,确保所有基类和成员对象都被正确初始化。

二、有参构造的强制调用(初始化列表)

规则
若父类或成员对象没有默认构造函数(只有带参数的构造函数),子类构造函数必须在初始化列表显式调用它们的有参构造函数,否则编译器报错(因为无法默认初始化)。

调用规则细节

  • 父类:用 父类名(参数) 调用,指定父类构造函数及参数。
  • 成员对象:用 成员对象名(参数) 调用,指定成员对象构造函数及参数。

示例验证(父类、成员对象均为有参构造)

class Father {
public:int money;// 父类有参构造(无默认构造)Father(int m) : money(m) { cout << "Father 有参构造:" << money << endl; }
};class Member {
public:int toy;// 成员对象有参构造(无默认构造)Member(int t) : toy(t) { cout << "Member 有参构造:" << toy << endl; }
};class Son : public Father {
private:// 子类包含的成员对象Member m; 
public:// 初始化列表:调用父类、成员对象的有参构造Son(int m_money, int m_toy) // 调用父类有参构造,初始化父类成员 money: Father(m_money),  // 调用成员对象有参构造,初始化成员对象 m 的 toym(m_toy)          { cout << "Son 构造" << endl; }
};int main() {Son son(100, 5); // 输出顺序:// Father 有参构造:100 → Member 有参构造:5 → Son 构造return 0;
}

避坑点
初始化列表的调用顺序由成员变量在类中的声明顺序决定,而非初始化列表的书写顺序。若顺序错误,可能导致未定义行为(如用未初始化的成员给其他成员赋值)。

8. 虚继承的原理

虚继承是 C++ 为解决多继承中的菱形继承问题(多个子类继承同一父类,导致父类成员在子类中重复存储)而设计的机制。其核心是通过虚基类指针和虚基类表,让多个子类共享同一父类的成员,避免数据冗余和访问冲突。

一、菱形继承问题(不使用虚继承)

场景
类 A 是类 B 和 C 的父类,类 D 同时继承 B 和 C。此时,D 中会包含两份 A 的成员(一份来自 B,一份来自 C),导致数据冗余和二义性。

示例(问题代码)

class A {
public:int data;A(int d) : data(d) {}
};class B : public A {
public:B(int d) : A(d) {}
};class C : public A {
public:C(int d) : A(d) {}
};class D : public B, public C {
public:D(int d1, int d2) : B(d1), C(d2) {}
};int main() {D d(10, 20);// 编译报错:data 二义性(B::data 和 C::data 冲突)// cout << d.data << endl; return 0;
}

问题
D 中存储了两份 A 的 dataB::data 和 C::data),访问 d.data 时编译器无法确定访问哪一份,引发二义性错误。

二、虚继承的解决方案

原理
虚继承通过在子类中添加虚基类指针(vbptr),指向虚基类表(vbtable)。虚基类表中记录了从该指针到公共祖先(如 A)成员的偏移量,确保多个子类(如 B 和 C)共享同一 A 的成员,避免数据冗余。

使用虚继承的代码

class A {
public:int data;A(int d) : data(d) {}
};// 虚继承 A
class B : virtual public A { 
public:B(int d) : A(d) {}
};// 虚继承 A
class C : virtual public A { 
public:C(int d) : A(d) {}
};class D : public B, public C {
public:// 必须显式调用 A 的构造(虚继承后,B 和 C 无法直接初始化 A)D(int d) : A(d), B(d), C(d) {} 
};int main() {D d(10);// 输出10(B 和 C 共享 A::data)cout << d.data << endl; return 0;
}

内存布局变化

  • B 和 C 中各有一个虚基类指针(vbptr),指向虚基类表。
  • 虚基类表中存储了 B/C 到 A 成员的偏移量,确保 B::data 和 C::data 实际指向同一 A::data
三、虚继承的优缺点

优点

  • 解决菱形继承的二义性和数据冗余问题,让公共基类成员只存储一份。

缺点

  • 增加内存开销(每个虚继承的子类需存储虚基类指针和虚基类表)。
  • 构造函数复杂(虚继承后,最终子类需显式调用公共基类的构造函数,无法依赖中间子类)。

最佳实践
虚继承是 “无奈之举”,实际开发中应尽量避免多继承(用组合、接口继承替代),因为多继承的复杂性(如虚继承的理解成本、构造顺序问题)远大于其带来的便利。

9. 纯虚函数与抽象类

纯虚函数是 C++ 实现抽象类接口的核心机制。它强制子类必须实现某些函数,确保继承体系的行为统一。

一、普通纯虚函数的定义与特性

定义
纯虚函数是在基类中声明的虚函数,格式为 virtual 返回值类型 函数名(参数列表) = 0;。纯虚函数不需要(也不能强制要求)在基类中实现函数体,但子类必须以 override 关键字重写该函数(否则子类也会成为抽象类,无法实例化)。

示例

class Base {
public:// 纯虚函数:基类只声明,不实现virtual void func() = 0; 
};class Derived : public Base {
public:// 子类必须重写纯虚函数void func() override { cout << "Derived::func 调用" << endl; }
};int main() {// 错误:抽象类不能实例化// Base b; Derived d;d.func(); // 输出:Derived::func 调用return 0;
}
二、纯虚函数的特殊用法(基类实现函数体)

规则
纯虚函数可以在基类中实现函数体,但这不是强制的。子类可以选择调用基类的实现(通过 Base::func()),但即便基类实现了函数体,子类仍需显式重写纯虚函数(否则子类是抽象类)。

示例验证

class Base {
public:// 纯虚函数声明virtual void func() = 0; 
};// 基类中实现纯虚函数的函数体(非强制,仅为示例)
void Base::func() { cout << "Base::func 调用" << endl; 
}class Derived : public Base {
public:// 子类必须重写纯虚函数void func() override { // 调用基类的实现(可选)Base::func(); cout << "Derived::func 调用" << endl; }
};int main() {Derived d;d.func(); // 输出:// Base::func 调用 → Derived::func 调用return 0;
}

注意
基类纯虚函数的实现体通常用于提供 “默认逻辑”,子类可选择复用或完全重写,但子类必须显式重写(否则无法实例化)。

三、纯虚函数对析构函数的影响

纯虚析构函数是特殊场景:基类若声明纯虚析构函数,必须提供函数体(否则链接报错,因为析构函数需要释放资源)。子类析构函数会自动调用基类析构函数,确保资源正确释放。

示例(纯虚析构函数)

class Base {
public:// 纯虚析构函数,必须实现函数体virtual ~Base() = 0; 
};// 基类纯虚析构函数的实现体
Base::~Base() { cout << "Base 析构函数调用" << endl; 
}class Derived : public Base {
public:~Derived() {cout << "Derived 析构函数调用" << endl;}
};int main() {Base* ptr = new Derived();// 销毁时:先 Derived 析构,再 Base 析构delete ptr; // 输出:// Derived 析构函数调用 → Base 析构函数调用return 0;
}

关键
纯虚析构函数的函数体必须定义(否则链接阶段报错),子类析构函数会隐式调用基类析构函数,保证继承体系的资源释放顺序。

10. 多态成立的条件

多态是 C++ 面向对象设计的核心特性,允许程序根据对象的实际类型(而非声明类型)调用对应的函数。其成立需满足以下三个条件:

https://github.com/0voice

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IntelliJ IDEA2024 错误‘http://start.spring.io/‘的初始化失败,请检查URL、网络和代理设置。

下载新版本的intellij idea2024创建项目时&#xff0c;服务器URL报错误http://start.spring.io/的初始化失败&#xff0c;请检查URL、网络和代理设置。错误消息&#xff1a;Cannot download http://start.spring.io/:Permission denied:getsockopt&#xff0c;具体如下图&#…

从零开始的云计算生活——第三十八天,避坑落井,Docker容器模块

一.故事背景 在综合使用了之前全部的知识完成项目之后&#xff0c;接下来将学习更简单的方法来对之前的命令进行使用&#xff0c;马上进入容器模块 二. Docker概述 Docker简介 Docker&#xff0c;翻译过来就是码头工人 Docker是一个开源的应用容器引擎&#xff0c;让开发者…

Python与自动化运维:构建智能IT基础设施的终极方案

Python与自动化运维:构建智能IT基础设施的终极方案 引言:运维革命的Python引擎 在DevOps理念席卷全球的今天,企业IT基础设施的复杂度呈指数级增长。某跨国银行的数据显示,采用Python构建的自动化运维体系使其服务器部署效率提升400%,故障响应时间缩短至原来的1/8。本文将…

HarmonyOS应用开发环境搭建以及快速入门介绍

下载并安装DevEco Studio&#xff0c;这是华为官方提供的HarmonyOS应用开发IDE。访问华为开发者联盟官网下载对应操作系统的版本。安装完成后&#xff0c;配置HarmonyOS SDK和必要的工具链。 确保计算机满足开发环境要求&#xff0c;包括Windows 10 64位或macOS 10.14及以上操…

RocketMQ与Kafka 消费者组的‌重平衡操作消息顺序性对比

RocketMQ 的重平衡机制本身不会直接影响消息顺序&#xff0c;但消费模式的选择和使用需注意以下细节&#xff1a;重平衡机制RocketMQ消费者组的重平衡策略是每隔20秒从Broker获取消费组的最新消费进度&#xff0c;并根据订阅信息重新分配消息队列。该策略主要影响消息拉取的均衡…

学习 Android(十四)NDK基础

学习 Android&#xff08;十四&#xff09;NDK基础 Android NDK 是一个工具集&#xff0c;可让我们使用 C 和 C 等语言以原生代码实现应用的各个部分。对于特定类型的应用&#xff0c;这可以帮助我们重复使用以这些语言编写的代码库。 接下来&#xff0c;我们将按照以下步骤进行…

宝塔(免费版9.2.0)的docker拉取仓库失败的加速方法

宝塔docker拉取仓库失败 完美加速方法_宝塔docker加速-CSDN博客 版本&#xff1a;免费版 9.2.0 https://docker.1ms.run 其他的试了很多 都不行 最后不要用宝塔的控制面板(很卡)&#xff0c;直接在linux中用命令行&#xff0c;效果就很好了。

文献解读-生境分析亚区域选择+2D_DL+3D_DL-局部晚期食管鳞状细胞癌新辅助化疗免疫治疗反应预测

研究标题&#xff1a;结合亚区域放射组学与多通道二维或三维深度学习模型预测局部晚期食管鳞状细胞癌&#xff08;LA-ESCC&#xff09;患者对新辅助化疗免疫治疗&#xff08;NACI&#xff09;的反应借鉴点&#xff1a;建模思路&#xff08;看流程图理解就够了&#xff09;引言食…

机器学习第四课之决策树

目录 简介 一.决策树算法简介 二. 决策树分类原理 1.ID3算法 1.1 熵值 1.2 信息增益 1.3 案例分析 ​编辑 2.C4.5 2.1 信息增益率 2.2.案例分析 3.CART决策树 3.1基尼值和基尼指数 3.2案例分析 三、决策树剪枝 四、决策树API 五、电信客户流失 六、回归树 七. 回归…

Java面试题和答案大全

一、Java基础知识 1. Java语言特点 题目: 请说明Java语言的主要特点? 答案: 面向对象:Java是纯面向对象的语言,支持封装、继承、多态 平台无关性:一次编译,到处运行(Write Once, Run Anywhere) 简单性:语法简洁,去掉了C++中的指针、多重继承等复杂特性 安全性:提…

用NAS如何远程访问:详细教程与实用技巧

在信息时代&#xff0c;家用NAS&#xff08;网络附加存储&#xff09;成为家庭数据存储和管理的热门设备。它不仅可以作为家庭照片、视频、工作文件的集中存储中心&#xff0c;还支持远程访问&#xff0c;方便用户随时随地获取数据。那么&#xff0c;如何配置和实现家用NAS的远…

Qt-桌面宠物

目录 一&#xff0c;演示&#xff08;部分功能&#xff09; 二&#xff0c;开发环境准备 三&#xff0c;部分代码实现 1.创建基础窗口 2.实现宠物动画 3.添加交互功能 4.系统托盘集成 5.行为模式实现 6.状态管理系统 7.资源打包部署 四&#xff0c;接受定制 一&…

C++编程学习(第19天)

局部变量和全局变量每一个变量都有其有效作用范围&#xff0c;这就是变量的作用域&#xff0c;在作用域以外是不能访问这些变量的。局部变量在一个函数内部定义的变量是局部变量&#xff0c;它只在本函数范围内有效&#xff0c;也就是说只有在本函数内才能使用他们&#xff0c;…

客流特征识别准确率提升 29%:陌讯多模态融合算法在零售场景的实战解析

原创声明本文为原创技术解析文章&#xff0c;涉及的技术参数与架构设计引用自《陌讯技术白皮书》&#xff0c;禁止任何形式的抄袭与转载。一、行业痛点&#xff1a;零售客流识别的技术瓶颈在零售数字化转型过程中&#xff0c;客流特征识别&#xff08;包括性别、年龄分层、停留…

YOLOv8/YOLOv11 C++ OpenCV DNN推理

首先需要将yolov8/yolov11的pt文件转为onnx文件 from ultralytics import YOLO model YOLO("best.pt") model.export(format"onnx",opset11,dynamicFalse) 本次C工具使用vs2017&#xff0c;需要下载OpenCV包&#xff1a;https://opencv.org/releases/&a…

【Mysql】日志--错误日志、二进制日志、查询日志、慢查询日志

错误日志:数据库出现错误时&#xff0c;进行故障排除默认位置&#xff1a;/var/log/mysqld.log查看日志位置show variables like %log_error%查看日志tail -50 /var/log/mysqld.log二进制日志&#xff1a;记录了所有的DDL语句和DML语句&#xff0c;不包含查询&#xff08;selec…

后端常用框架环境与软件详解

一、基础运行环境 1. JDK&#xff08;Java Development Kit&#xff09; 定义&#xff1a;Java 开发工具包&#xff0c;包含编译器、运行时环境&#xff08;JRE&#xff09;及核心类库 作用&#xff1a;提供 Java 程序开发和运行的基础环境&#xff0c;是所有 Java 应用的必备依…

本地服务器端部署基于大模型的通用OCR项目——dots.ocr

本地服务器端部署基于大模型的通用OCR项目——dots.ocrdots.ocr相关介绍本地服务器端部署第一步&#xff1a;安装cuda12.8与CUDNN8.9.7第二步&#xff1a;创建项目所需的依赖环境第三步&#xff1a;启动项目第四步&#xff1a;测试第五步&#xff1a;文本解析相关性测试第六步&…

Text2SQL 智能问答系统开发-spider验证集(三)

概述 已完成 基础 Text2SQL 功能实现 实现用户输入自然语言问题后&#xff0c;系统能够自动生成 SQL 并执行返回结果。用户交互优化 支持用户通过补充信息对查询进行调整&#xff0c;提升易用性。模糊时间处理机制 对“最近”“近期”等模糊时间关键词进行补全或引导&#xf…

ElementUI常用的组件展示

文章目录1、要使用ElementUI先导入组件库2、自定义表头&#xff0c;可以改为添加和批量删除的按钮3、Dialog模态框&#xff0c;主要用于添加和修改时展示信息4、抽屉5、消息提示&#xff1a;用于提示是否操作成功6、询问&#xff1a;常用于询问是否确定删除7、批量选择复选框8、…