C++基础从0到1入门编程(六)- 类继承、类多态

news2025/1/17 9:05:11

系统学习C++,本章将记录类继承类多态的相关概念
方便自己日后复习,错误的地方希望积极指正
往期文章:
C++基础从0到1入门编程(一)
C++基础从0到1入门编程(二)
C++基础从0到1入门编程(三)
C++基础从0到1入门编程(四)
C++基础从0到1入门编程(五)
参考视频:
1.黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难
2.系统化学习C++

1 类继承

1.1 基本概念

继承:一个类从另一个类获取成员变量和成员函数的过程
语法:

class 派生类名: [继承方式] 基类名
{
	派生类新增加的成员
}

被继承的类称为基类或父类;继承的类称为派生类或子类
使用继承的场景
(1)新创建的类和现有的类相似,只是多出若干成员变量或成员函数,可以使用继承

#include <iostream>
using namespace std;
class CallComers
{
public:
    string name_;
    string tel_;
    CallComers() { name_ = "Big"; tel_ = "123"; }
    void sing() { cout << "I am a bird\n"; }
    void setname(const string& name) { name_ = name; }
    void settel(const string& tel) { tel_ = tel; }
};
class CGirl : public CallComers
{
public:
    int bh_;
    CGirl() { bh_ = 8; }
    void show() { cout << bh_ << ' ' << name_ << ' ' << tel_ << endl; }
};
int main()
{
    CGirl g;
    g.name_ = "Small";
    g.show(); // 8 Small 123
}

(2)当需要创建多个类时,如果拥有很多相似的成员变量或成员函数,可以将这些类提取出来,定义为基类,然后从基类继承

class Sort 
{
	int  data[30];
	void print()
};
class BubbleSort :public Sort
{
	void sort();
};
class ShellSort :public Sort
{
	void sort();
};
1.2 继承方式

类成员访问权限:public - > protected - > private
public成员在类外可以访问,private成员只能在类的成员函数中访问

不考虑继承关系,protected成员和private成员一样,类外不能访问。当存在继承关系,基类的protected成员可以在派生类中访问,而基类的private成员不能在派生类中访问

继承方式:public、protected、private。如果不写,默认为private
在这里插入图片描述
(1)基类成员在派生类中的访问权限不得高于继承方式中指定的权限。继承方式中的public、protected、private是用来指明基类成员在派生类中的最高访问权限的
(2)不管继承方式如何,基类中的private成员在派生类中始终不能使用,不能在派生类的成员函数中访问或调用
(3)如果希望基类的成员能够被派生类继承并且毫无障碍地使用,那么这些成员只能声明为public 或protected;只有那些不希望在派生类中使用的成员才声明为private
(4)如果希望基类的成员既不向外暴露(不能通过对象访问),还能在派生类中使用,那么只能声明为 protected

由于private和protected继承方式会改变基类成员在派生类中的访问权限,导致继承关系复杂,在实际开发中,一般使用public

(5)在派生类中,可以通过基类的公有成员函数间接访问基类的私有成员
(6)使用 using 关键字可以改变基类成员在派生类中的访问权限

using只能改变基类中public和protected成员的访问权限,不能改变private成员的访问权限,因为基类中的private成员在派生类中是不可见的,根本不能使用

#include <iostream>
using namespace std;
class A
{
public:
    int a_ = 10;
protected:
    int b_ = 20;
private:
    int c_ = 30;
};
class B :public A
{
public:
    using A::b_;
    // using A::c_; // 报错
private:
    using A::a_;
};
int main()
{
    B b;
    // b.a_ = 10;
    b.b_ = 21;
}
1.3 继承的对象模型
  1. 创建派生类对象,先调用基类的构造函数,再调用派生类的构造函数。销毁派生类对象,先调用派生类的析构函数,再调用基类的析构函数。如果手工调用派生类的析构函数,也会调用基类的析构函数
    基类(构造函数)-> 派生类(构造函数) -> 派生类(析构函数) -> 基类(析构函数)
  2. 创建派生类对象只会申请一次内存,派生类对象包含了基类对象的内存空间,this指针是相同的
  3. 创建派生类对象,先初始化基类对象,再初始化派生类对象
  4. 对派生类对象用sizeof得到的是基类所有成员(包括私有成员)+ 派生类对象所有成员的大小
  5. 在C++中,不同继承方式的访问权限只是语法上的处理
  6. 对派生类对象用memset()会清空基类私有成员
memset(p, 0, sizeof(B));
  1. 用指针可以访问到基类中的私有成员(内存对齐)
*((int*)p + 2) = 123;
#include <iostream>
#include <cstring>
using namespace std;
void* operator new(size_t size)
{
    void* ptr = malloc(size);
    cout << ptr << ' ' << size << endl;
    return ptr;
}
void operator delete(void* ptr)
{
    if (ptr == 0) return;
    free(ptr);
    cout << "Free\n";
}
class A
{
public:
    int a_ = 10;
protected:
    int b_ = 20;
private:
    int c_ = 30;
public:
    A()
    {
        cout << this << endl;
        cout << &a_ << endl;
        cout << &b_ << endl;
        cout << &c_ << endl;
    }
    void func()
    {
        cout << a_ <<' ' << b_ << ' ' << c_ << endl;
    }
};
class B:public A
{
public:
    int d_ = 40;
    B()
    {
        cout << this << endl;
        cout << &a_ << endl;
        cout << &b_ << endl;
        cout << &d_ << endl;
    }
    void func1() { cout << d_ << endl; }
};
int main()
{
    cout << sizeof(A) << endl; // 12
    cout << sizeof(B) << endl; // 16
    B* p = new B;
    p->func(); p->func1();
//    memset(p, 0, sizeof(B));
//    p->func(); p->func1();
    *((int*)p + 2) = 123;
    p->func(); p->func1();
    delete p;
}
1.4 构造基类

派生类构造函数的要点:
(1)创建派生类对象,程序先调用基类构造函数,然后再调用派生类构造函数
(2)没有指定基类构造函数,将使用基类的默认构造函数
(3)可以用初始化列表指明要使用的基类构造函数
(4)基类构造函数负责初始化被继承的数据成员;派生类构造函数用于初始化新增的数据成员
(5)派生类的构造函数总是调用一个基类构造函数,包括拷贝构造函数

#include <iostream>
using namespace std;
class A
{
public:
    int a_;
private:
    int b_;
public:
    A() : a_(0), b_(0)
    {
        cout << "Base class MorenGouzao\n";
    }
    A(int a, int b) : a_(a), b_(b)
    {
        cout << "Base class Gouzao\n";
    }
    A(const A &a) : a_(a.a_), b_(a.b_)
    {
        cout << "Base class KaoBeiGouzao\n";
    }
    void showA()
    {
        cout << a_ << ' ' << b_ << endl;
    }
};
class B:public A
{
public:
    int c_;
    B() : c_(0), A()
    {
        cout << "Moren GouzaoB()\n";
    }
    B(int a,int b, int c) : A(a,b), c_(c)
    {
        cout << "B(int a,int b, int c)\n";
    }
    B(const A& a, int c) : A(a), c_(c)
    {
        cout << "B(const A& a, int c)\n";
    }
    void showB()
    {
        cout << c_ << endl;
    }
};
int main()
{
    B b1;
    b1.showA(); // 0 0
    b1.showB(); // 0

    B b2(1, 2, 3);
    b2.showA(); // 1 2
    b2.showB(); // 3

    A a(10, 20);
    B b3(a, 20);
    b3.showA(); // 10 20
    b3.showB(); // 20
}
1.5 名字遮蔽与类作用域

如果派生类中的成员(包括成员变量和成员函数)和基类中的成员重名,通过派生类对象或者在派生类的成员函数中使用该成员时,将使用派生类新增的成员,而不是基类的

#include <iostream>
using namespace std;
class A
{
public:
    int a_ = 30;
    void func() { cout << "A func()\n"; }
};
class B:public A
{
public:
    int a_ = 80;
    void func() { cout << "B func()\n"; }
};
int main()
{
    B b;
    cout << b.a_ << endl; // 80
    b.func();             // B func()
}

Tip:基类的成员函数和派生类的成员函数不会构成重载,如果派生类有同名函数,那么就会遮蔽基类中的所有同名函数(因为作用域)

在成员名前面加类名和域解析符可以访问对象的成员
如果不存在继承关系,类名和域解析符可以省略不写

#include <iostream>
using namespace std;
class A
{
public:
    int a_ = 30;
    void func() { cout << "A func()\n"; }
    void func(int a) { cout << "A func(int a)\n"; }
};
class B:public A
{
public:
    int a_ = 80;
    //void func() { cout << "B func()\n"; }
};
int main()
{
    B b;
    cout << b.a_ << endl; // 80
    b.func();             // B func()
    b.func(1);            // 把派生类的func()注释掉可以运行
}

当存在继承关系时,基类的作用域嵌套在派生类的作用域中。如果成员在派生类的作用域中已经找到,就不会在基类作用域中继续查找;如果没有找到,则继续在基类作用域中查找
在成员的前面加上类名和域解析符,就可以直接使用该作用域的成员
在这里插入图片描述

#include <iostream>
using namespace std;
class A
{
public:
    int a_ = 10;
    void func() { cout << "A func()\n"; }
};

class B : public A
{
public:
    int a_ = 20;
    void func() { cout << "B func()\n"; }
};
class C : public B
{
public:
    int a_ = 30;
    void func() { cout << "C func()\n"; }
    void show()
    {
        cout << C::a_ << ' ' << B::a_ << ' ' << B::A::a_ << endl;
    }
};
int main()
{
    C c;
    cout << c.C::a_ << endl; // 30
    cout << c.B::a_ << endl; // 20
    cout << c.B::A::a_ << endl;// 10
    c.C::func(); // C func()
    c.B::func(); // B func()
    c.B::A::func();// A func()
    c.show(); // 30 20 10
}
1.6 继承的特殊关系

派生类和基类之间的特殊关系
(1)如果继承方式是公有的,派生类对象可以使用基类成员
(2)派生类对象赋值给基类对象(包括私有成员),会舍弃非基类的成员
(3)基类指针可以在不显示转换的情况下指向派生类对象
(4)基类引用可以在不显示转换的情况下指向派生类对象
Tip:

(1)基类指针或引用只能调用基类的方法,不能调用派生类的方法
(2)用派生类构造基类
(3)如果函数形参是基类,实参可以用派生类
(4)C++要求指针和引用类型与赋给的类型匹配,这一规则对继承来说是例外。但是,这种例外只是单向的,不可以将基类对象和地址赋给派生类引用和指针(没有价值)

#include <iostream>
using namespace std;
class A
{
public:
    int a_ = 0;
private:
    int b_ = 0;
public:
    void show()
    {
        cout << a_ << ' ' << b_ << endl;
    }
    void setb(int b) { b_ = b; }
};
class B:public A
{
public:
    int c_ = 0;
    void show() { cout << a_ << ' '  << c_ << endl; }
};
int main()
{
    B b;
    A* a = &b;

    b.a_ = 10;
    b.setb(20);
    b.c_ = 30;
    b.show(); // 10 30

    a->a_ = 11;
    a->setb(12);
    a->show(); // 11 12
}
1.7 类继承 - 多继承与虚继承

多继承语法:

class B : public A, public C
{
	int a_ = 10;
}

菱形继承:

在这里插入图片描述
虚继承可以解决菱形继承的二义性数据冗余问题
有了多继承,就存在菱形继承,有了菱形继承就有虚继承,变得更复杂
不提倡使用多继承,只有在比较简单和不出现二义性的情况下才使用多继承,能用单一继承解决的问题就不要用多继承
多继承:

#include <iostream>
using namespace std;
class A1 {
public:
    int a_ = 10;
};
class A2 {
public:
    int a_ = 20;
};
class B :public A1, public A2 {
public:
    int a_ = 30;
};
int main()
{
    B b;
    cout << b.a_ << endl;    // 30
    cout << b.A1::a_ << endl;// 10
    cout << b.A2::a_ << endl;// 20
}

菱形继承:

#include <iostream>
using namespace std;
class A
{
public:
    int a_ = 10;
};
class B : virtual public A {};
class C : virtual public A {};
class DD : public B, public C {};
int main()
{
    DD d;
    d.a_ = 20;
    cout << d.a_ << endl; // 20
    cout << &d.B::a_ << ' ' << &d.C::a_ << endl; // 0x47d1ffc90 0x47d1ffc90
}

2 类多态

2.1 多态的基本概念

基类指针只能调用基类的成员函数,不能调用派生类的成员函数。

如果在基类的成员函数前加virtual关键字,把它声名为虚函数,基类指针就可以调用派生类中同名的成员函数,通过派生类中的成员函数,就可以访问派生对象的成员变量

有了虚函数,基类指针指向基类对象时就使用基类的成员函数和数据,指向派生类对象时就使用派生类的成员函数和数据,基类指针表现出了多种形式,这种现象称为多态
基类引用也可以使用多态
Tip:
(1)只需要在函数声名的时候加上virtual关键字,函数定义时不能加
(2)派生类中重定义虚函数,函数特征要相同
(3)基类中定义了虚函数时,如果派生类没有重定义该函数,那么将使用基类的虚函数
(4)在派生类中重定义了虚函数的情况下,如果想使用基类的虚函数,可以加类名和域解析符
(5)如果要在派生类中重新定义基类的函数,则将它设置为虚函数;否则,不要设置为虚函数
有两方面好处:(1)普通函数效率更高(2)指出不要重新定义该函数

#include <iostream>
using namespace std;
class CAllComers{
public:
    int bh_ = 0;
    virtual void show() { cout << "CAllComers::show() " << bh_ << endl; }
    virtual void show(int a) { cout << "CAllComers::show(int a) " << bh_ << endl; }
};

class CGirl : public CAllComers {
public:
    int age_ = 0;
    void show() { cout << "CGirl::show() " << bh_ << ' ' << age_ << endl; }
    void show(int a) { cout << "CGirl::show(int a) " << bh_ << ' ' << age_ << endl; }
};
int main()
{
    CAllComers a;
    a.bh_ = 3; // 创建基类对象并对成员赋值
    CGirl g;
    g.bh_ = 8; g.age_ = 23;// 创建派生类对象并对成员赋值
    CAllComers* p;// 声明基类指针
//    p = &a;
//    p->show(); //CAllComers::show() 3 // 让基类指针指向基类对象,并调用虚函数
//    p->show(5);
    p = &g;
    p->show(); // CGirl::show() 8 23 // 让基类指针指向派生类对象,并调用虚函数
    p->show(5);
    p->CAllComers::show(5);
}
2.2 多态的应用场景

在这里插入图片描述

(1)基类的虚函数实现基本功能
(2)派生类重新定义虚函数,扩展功能、提升功能
(3)实现个性化功能

#include <iostream>
using namespace std;

class Hero
{
public:
    int viability;
    int attack;
    virtual void skill1() { cout << "One skill1" << endl; }
    virtual void skill2() { cout << "Two skill2" << endl; }
    virtual void uskill() { cout << "uskill" << endl; }
};

class XS : public Hero
{
public:
    void skill1() { cout << "XS skill1" << endl; }
    void skill2() { cout << "XS skill2" << endl; }
    void uskill() { cout << "XS uskill" << endl; }
};
class HX : public Hero
{
public:
    void skill1() { cout << "HX skill1" << endl; }
    void skill2() { cout << "HX skill2" << endl; }
    void uskill() { cout << "HX uskill" << endl; }
};
int main()
{
    int id = 0;
    cout << "Please input hero: " << endl;
    cin >> id;
    // 创建基类指针,让它指向派生类对象,用基类指针调用派生类的成员函数
    Hero* ptr = nullptr;
    if (id == 1)
    {
        ptr = new XS;
    }
    else if (id == 2)
    {
        ptr = new HX;
    }
    if (ptr != nullptr)
    {
        ptr->skill1();
        ptr->skill2();
        ptr->uskill();
        delete ptr;
    }
}
2.3 多态的对象类型

类的普通成员函数地址是静态的,在编译阶段指定

(1)如果基类中有虚函数,对象的内存模型中有一个虚函数表,表中存放了基类的函数名和地址
(2)如果派生类中重定义了基类的虚函数,创建派生对象时,将用派生类的函数取代虚函数表中基类的函数

C++中的多态分为两种:静态多态与动态多态
静态多态:编译时的多态,在编译时期就已经确定要执行了的函数地址了;主要有函数重载和函数模板
动态多态:动态绑定,在运行时才去确定对象类型和正确选择需要调用的函数,一般用于解决基类指针或引用派生类对象调用类中重写的方法(函数)时出现的问题

调用普通成员函数的效率比调用虚函数的效率更高,所以如果不考虑多态,不要把普通成员函数设置为虚函数

2.4 如何析构派生类

(1)构造函数不能继承,创建派生类对象,先执行基类构造函数,再执行派生类构造函数
(2)析构函数不能继承,销毁派生类对象时,先执行派生类析构函数,再执行基类析构函数
(3)派生类析构函数执行完,会自动调用基类的析构函数
(4)如果手工的调用派生类的析构函数,也会自动调用基类函数
析构派生类
1.析构派生类对象时,会自动调用基类的析构函数。与构造函数不同的是,在派生类的析构函数中不用显式地调用基类的析构函数,因为每个类只有一个析构函数,编译器知道如何选择,无需程序员干涉

2.析构函数可以手工调用,如果对象中有堆内存

delete ptr;
ptr = nullptr;

3.用基类指针指向派生类对象时,delete基类指针调用的时基类的析构函数,不是派生类的,如果希望调用派生类的析构函数,就要把基类的析构函数设置为虚函数

4.C++编译器对虚析构函数做了特别的处理

5.对于基类,即使它不需要析构函数,也应该提供一个空虚析构函数,不然析构派生类对象不执行

6.赋值运算符函数不能继承,派生类继承的函数的特征标与基类完全相同,但赋值运算符函数的特征标随类而异,它包含了一个类型为其所属类的形参

7.友元函数不是类成员,不能继承

#include <iostream>
using namespace std;

class AA
{
public:
    AA() { cout << "Base Gouzao\n"; }
    virtual void func() { cout << "Base func()\n"; }
    virtual ~AA() { cout << "Base Xigou\n"; }
};
class BB : public AA
{
public:
    BB() { cout << "Pai Gouzao\n"; }
    void func() { cout << "Pai func()\n"; }
    ~BB() { cout << "Pai Xigou\n"; }
};
int main()
{
    AA *a = new BB;
    a->func();
    delete a;
}
2.5 纯虚函数和抽象类

纯虚函数是一种特殊的虚函数,在某些情况,基类中不能对虚函数给出有意义的实现,把它声名为纯虚函数
语法:virtual 返回值类型 函数名(参数列表) = 0
纯虚函数在基类中为派生类保留一个函数的名字,以便派生类进行重定义,如果在基类中没有保留函数名字,则无法支持多态性

含有纯虚函数的类被称为抽象类,不能实例化对象可以创建指针和引用

派生类必须重定义抽象类中的纯虚函数,否则也属于抽象类(不能实例化对象)

基类的纯虚析构函数也需要实现,为啥声名析构函数为纯虚析构函数?
有时候,想使一个类成为抽象类,刚好没有任何纯虚析构函数,在想要成为抽象类中声名一个纯虚析构函数

#include <iostream>
using namespace std;

class AA
{
public:
    AA() { cout << "Base Gouzao\n"; }
    virtual void func() = 0;// { cout << "Base func()\n"; }
    virtual ~AA() { cout << "Base Xigou\n"; }
};
class BB : public AA
{
public:
    BB() { cout << "Pai Gouzao\n"; }
    void func() { cout << "Pai func()\n"; }
    ~BB() { cout << "Pai Xigou\n"; }
};
int main()
{
    AA *a = new BB;
    a->func();
    delete a;
}

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

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

相关文章

西瓜书-主要符号表

主要符号表 LaTeX符号说明How to read letter?\mathit{x}标量\boldsymbol{x}向量\mathrm{x}变量集\mathbf{A}矩阵\mathbf{I}单位阵\mathcal{X}样本空间或状态空间calligraphic X\mathcal{D}概率分布Ɗ calligraphic D\mathit{H}数据样本&#xff08;数据集)\mathcal{H}假设空…

智能优化算法应用:基于差分进化算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于差分进化算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于差分进化算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.差分进化算法4.实验参数设定5.算法结果6.参考…

IM通信技术快速入门:短轮询、长轮询、SSE、WebSocket

文章目录 前言即时通讯常用技术 短轮询&#xff08;Short Polling&#xff09;实现原理优点缺点 长轮询(Long Polling)实现原理改进点基于iframe的长轮询实现原理总结 Server-Sent Events&#xff08;SSE&#xff09;实现原理浏览器对 SSE 的支持情况SSE vs WebSocket总结 WebS…

基于英特尔平台及OpenVINO2023工具套件优化文生图任务

当今&#xff0c;文生图技术在很多领域都得到了广泛的应用。这种技术可以将文本直接转换为逼真的图像&#xff0c;具有很高的实用性和应用前景。然而&#xff0c;由于文生成图任务通常需要大量的计算资源和时间&#xff0c;如何在英特尔平台上高效地完成这些计算是一个重要的挑…

基于Java SSM框架+Vue实现企业公寓后勤管理系统项目【项目源码+论文说明】

基于java的SSM框架Vue实现企业宿舍后勤管理网站演示 摘要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所…

RC低通滤波电路直接带载后会发生什么?

1、滤波的含义 滤波是频域范畴&#xff0c;它说的是不同频率的信号经过一个电路处理后&#xff0c;信号发生变化的问题&#xff0c;变化包含了原始信号幅值和相位的变化&#xff0c;滤波电路对信号的幅值做出的响应称为幅频响应&#xff0c;对信号相位做出的反应称为相频响应。…

【MySQL】视图 + 用户管理

视图 前言正式开始视图用户管理user表创建新用户修改用户密码权限管理给用户赋权剥夺权限 前言 本篇所讲的视图和我上一篇事务中所讲的读视图不是一个东西&#xff0c;二者没有任何关系&#xff0c;如果看过我前一篇博客的同学不要搞混了。 其实视图和用户管理本来是想着分开…

perl脚本批量处理代码中的中文注释乱码的问题

代码中统一使用utf-8编码是最好的&#xff0c;但是有一些多人合作的项目或者一些历史遗留代码&#xff0c;常见一些中文注释乱码的问题。这里以一个开源项目evpp为例子 evpp。以项目中的一个commit id为例&#xff1a; 477033f938fd47dfecde43c82257cd286d9fa38e &#xff0c; …

数据结构之堆排序以及Top-k问题详细解析

个人主页&#xff1a;点我进入主页 专栏分类&#xff1a;C语言初阶 C语言程序设计————KTV C语言小游戏 C语言进阶 C语言刷题 数据结构初阶 欢迎大家点赞&#xff0c;评论&#xff0c;收藏。 一起努力 目录 1.前言 2.堆排序 2.1降序排序 2.2时间复杂…

充电桩新老国标兼容性分析

1、背景介绍 1.1、充电桩相关标准发展历程 1.2、兼容性分析历史 1.3、兼容性分析的目的 1.4、兼容性分析的内容 2、B类协议兼容性分析 2.1、协议分层结构 2.2、链路层分析 2.3、版本协商与链路检测 ## 2.4、传输层分析 2.5、应用层 2.5.1、应用层数据 2.5.2、应用层数据…

谈谈MYSQL索引

基本介绍 索引是帮助MySQL高效获取数据的数据结构&#xff0c;主要是用来提高数据检索的效率&#xff0c;降低数据库的IO成本&#xff0c;同时通过索引列对数据进行排序&#xff0c;降低数据排序的成本&#xff0c;也能降低了CPU的消耗。 通俗来说, 索引就相当于一本书的目录,…

QML中常见布局方法

目录 引言常见方法锚定&#xff08;anchors&#xff09;定位器Row、ColumnGridFlow 布局管理器RowLayout、ColumnLayoutGridLayoutStackLayout 总结 引言 UI界面由诸多元素构成&#xff0c;如Label、Button、Input等等&#xff0c;各种元素需要按照一定规律进行排布才能提高界…

Java数据结构之《构造哈夫曼树》题目

一、前言&#xff1a; 这是怀化学院的&#xff1a;Java数据结构中的一道难度中等(偏难理解)的一道编程题(此方法为博主自己研究&#xff0c;问题基本解决&#xff0c;若有bug欢迎下方评论提出意见&#xff0c;我会第一时间改进代码&#xff0c;谢谢&#xff01;) 后面其他编程题…

kgma转换flac格式、酷狗下载转换车载模式能听。

帮朋友下载几首歌到U盘里、发现kgma格式不能识别出来&#xff0c;这是酷狗加密过的格式&#xff0c;汽车不识别&#xff0c;需要转换成mp3或者flac格式&#xff0c;网上的一些辣鸡软件各种收费、限制、广告&#xff0c;后来发现一个宝藏网站&#xff0c;可以在线免费转换成flac…

长度最小的子数组(Java详解)

目录 题目描述 题解 思路分析 暴力枚举代码 滑动窗口代码 题目描述 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条…

MyBatis自动生成代码(扩展)

可以利用Mybatis-Generator来帮我们自动生成文件 1、自动生成实体类 可以帮助我们针对数据库中的每张表自动生成实体类 2、自动生成SQL映射文件 可以帮助我们针对每张表自动生成SQL配置文件&#xff0c;配置文件里已经定义好对于该表的增删改查的SQL以及映射 3、自动生成接…

数据层融合、特征层融合和决策层融合是三种常见的数据融合方式!!

文章目录 一、数据融合的方式有什么二、数据层融合三、特征层融合&#xff1a;四、决策层融合&#xff1a; 一、数据融合的方式有什么 数据层融合、特征层融合和决策层融合是三种常见的数据融合方式。 二、数据层融合 定义&#xff1a;数据层融合也称像素级融合&#xff0c;…

Chat-GPT原理

GPT原理 核心是基于Transformer 架构 英文原文&#xff1a; ​ Transformers are based on the “attention mechanism,” which allows the model to pay more attention to some inputs than others, regardless of where they show up in the input sequence. For exampl…

10 分钟解释 StyleGAN

一、说明 G在过去的几年里&#xff0c;生成对抗网络一直是生成内容的首选机器学习技术。看似神奇地将随机输入转换为高度详细的输出&#xff0c;它们已在生成图像、生成音乐甚至生成药物方面找到了应用。 StyleGAN是一种真正推动 GAN 最先进技术向前发展的 GAN 类型。当Karras …