C++(第五天----多继承、虚继承、虚函数、虚表)

news2024/9/21 21:59:36

一、继承对象的内存空间

构造函数调用顺序,先调用父类,再调用子类

#include<iostream>

using namespace std;

//基类   父类
class Base{
public: //公有权限   类的外部  类的内部 
        Base(){cout<<"Base()"<<endl;}
        Base(int a):baseA(a)
        {
            cout<<"Base(int a)"<<endl;
        }

        ~Base(){cout<<"~Base()"<<endl;}

        void setData(int a){
            baseA = a;
        }
        void show(){
            cout<<"baseA:"<<baseA<<"\t addr:"<<&baseA<<endl;
        }
protected: //保护权限  类的内部  子类
        
private: //私有权限  类的内部
        int baseA;
};

//子类  派生类
class Child: public Base
{
public: //公有权限   类的外部  类的内部 
        //在参数列表中指定 父类的构造函数
        Child():Base(100)
        {
            cout<<"Child()"<<endl;
        }
        Child(int a,int b):Base(a),childA(b)
        {
            cout<<"Child(int a)"<<endl;
        }

        ~Child(){cout<<"~Child()"<<endl;}

        void show(){
            Base::show();
            cout<<"childA:"<<childA<<"\t addr:"<<&childA<<endl;
        }
protected: //保护权限  类的内部

private: //私有权限  类的内部
        int childA;   
         
};


int main()
{
    Child mya(100,200);

    cout<<"mya size:"<<sizeof(mya)<<"\t addr:"<<&mya<<endl;

    mya.show();
}

打印结果:

gec@ubuntu:/mnt/hgfs/GZ22229/14C++/05/1-code$ ./a.out 
Base(int a)
Child(int a)
mya size:8     addr:0x7ffed6dc6630
baseA:100     addr:0x7ffed6dc6630
childA:200     addr:0x7ffed6dc6634
~Child()
~Base()

在这里插入图片描述
注意:
1、子类调用成员函数的时候会检测该成员函数在子类中是否存在,如果存在就调用自己的, 如果不存在就调用 父类的(前提是父类要有这个函数)
2、如果子类和父类存在同名函数,那么在子类中 父类的函数成员会被隐藏,默认调用的就是子类函数成员。如果要调用父类的函数成员必须添加类名和作用域。

mya.Base::showData();

练习1:
设计一个基类动物类(属性:体重,颜色,年龄 行为:跑,吃,睡),构造方法初始化属性
设计一个猫类继承动物类(属性:体重,颜色,年龄,品种 行为:跑吃睡,抓老鼠,叫)
定义一个猫对象–咖菲猫,调用猫的喊叫行为,抓老鼠行为 ,输出猫的属性

练习2:编写一个输出学生和教师数据的程序,学生数据有编号、姓名、年龄、学号和成绩;教师数据有编号、姓名、年龄、职称和部门。要求声明一个 person 类,并作为学生数据操作类 student 和教师数据操作类 teacher 的基类

#include <iostream>
#include <cstring>
//将命名空间打开
/*
设计一个基类 动物类(属性:体重、颜色、年龄 、性别    行为:吃喝拉撒)
设计一个猫类 继承动物类(属性:体重、颜色、年龄 、性别、    行为:吃喝拉撒、抓老鼠)
定义一个猫对象 ---断尾猫,调用猫的行为*/
using namespace std;
//动物类
class zoon{
public:   //公有权限
    zoon(int weight,int age, const char * color){
        this->weight = weight;
        this->age = age;
        strcpy(this->color,color);
    }
    void show(){
        cout << "weight:" << weight <<endl;
        cout << "age:"   << age <<endl;
        cout << "color:"  << color <<endl;
    }
protected:
    //私有属性
    int weight;    //体重
    int age;         //年龄
    char color[256];  //颜色
};
//猫类
class cat:public zoon
{
public:   //公有权限
    cat(int weight,int age,const char * color,const char *type):zoon(weight,age,color) {
        strcpy(this->type,type);
    }
    void show(){
        cout << "weight:" << weight <<endl;
        cout << "age:"   << age <<endl;
        cout << "color:"  << color <<endl;
        cout << "type:"  << type <<endl;
    }
    void behavior(){
        cout << "behavior" <<endl; 
    }
private:
    //私有
    char type[256];
    // cat Broken_tail(10,6,"white","BrokenTail");
};
int main()
{
    cat mya(10,6,"white","BrokenTail");
    mya.show();
    mya.behavior();  //行为
    
    
    return 0;
}

二、多继承

1、格式

class 子类:继承方式  基类1,继承方式  基类2 
{
    变量成员
    函数成员
};

2、例子

#include <iostream>


using namespace std;


//羊类
class Sheep{


public:
    Sheep(){
        cout<<"Sheep()"<<endl;
    }
    Sheep(int a):dataA(a)
    {
        cout<<"Sheep(int a)"<<endl;
    }
    ~Sheep(){
        cout<<"~Sheep()"<<endl;
    }
    void show(){
        cout<<"dataA value:"<<dataA<<"\t addr:"<<&dataA<<endl;
     }
    int dataA;
};


//驼类
class Tuo{


public:
    Tuo(){
        cout<<"Tuo()"<<endl;
    }
    Tuo(int a):dataB(a)
    {
        cout<<"Tuo(int a)"<<endl;
    }
    ~Tuo(){
        cout<<"~Tuo()"<<endl;
    }
    void show(){
        cout<<"dataB value:"<<dataB<<"\t addr:"<<&dataB<<endl;
     }
    int dataB;
};




//羊驼类
//多继承 的时候 基类的构造函数执行的顺序 跟  继承的先后顺序有关
class SheepTuo:public Sheep,public Tuo
{
public:
    //在构造函数的参数列表中 指定 基类的构造函数
    SheepTuo(int a,int b):Tuo(b),Sheep(a)
    {
        cout<<"SheepTuo()"<<endl;
    }
    ~SheepTuo(){
        cout<<"~SheepTuo()"<<endl;
    }
    //在子类中重写 基类的同名函数,那么基类中的同名函数就会自动隐藏
    void show(){
        cout<<"dataA value:"<<dataA<<"\t addr:"<<&dataA<<endl;
        cout<<"dataB value:"<<dataB<<"\t addr:"<<&dataB<<endl;
        cout<<"dataC value:"<<dataC<<"\t addr:"<<&dataC<<endl;
    }
    int dataC;
};




int main()
{
    //派生类对象的实例化
    SheepTuo mya(10,20);

    cout<<"mya size:"<<sizeof(mya)<<"\tmya addr:"<<&mya<<endl;

    mya.show();

    //通过基类的类名显示调用
    //mya.Sheep::show();

    return 0;
}


结果:
mylinux@ubuntu:/mnt/hgfs/13C++编程/04/1-code$ ./a.out 
A()
B()
C()
dataA addr:0x7fffd8f7f420 dataB addr:0x7fffd8f7f424 dataC addr:0x7fffd8f7f428
~C()
~B()
~A()

总结:

  • 多继承的时候,创建子类对象构造函数执行的顺序 羊—》驼----》羊驼 ,跟基类继承的先后顺序有关
  • 在派生类的构造函数初始化列表中指定基类的构造函数
    3、内存结构图
    在这里插入图片描述
    思考:如果多个基类中有同名的函数,那么创建子类的对象,然后进行调用,会发生什么情况?怎么解决

情况:编译错误,语法不通过
解决: 1. 在子类中重新实现函数,父类函数就会自动隐藏
2. 通过父类类名显示调用

三、多继承中的菱状继承(环状继承)

1、概念
多继承中的多级继承的时候,父类的父类出现公共的基类
2、例子
在这里插入图片描述

A--->D   C-->D   B-->A、C

这个继承会使D创建两个对象

#include <iostream>


using namespace std;


//动物类
class Animal{
public:
    Animal(){
        cout<<"Animal()"<<endl;
    }
    Animal(int a):dataD(a)
    {
        cout<<"Animal(int a)"<<endl;
    }
    ~Animal(){
        cout<<"~Animal()"<<endl;
    }


    int dataD;
};




//羊类 --继承于 动物类
class Sheep:public Animal{


public:
    Sheep(){
        cout<<"Sheep()"<<endl;
    }
    Sheep(int a):dataA(a)
    {
        cout<<"Sheep(int a)"<<endl;
    }
    ~Sheep(){
        cout<<"~Sheep()"<<endl;
    }
    void show(){
        cout<<"dataA value:"<<dataA<<"\t addr:"<<&dataA<<endl;
     }
    int dataA;
};


//驼类
class Tuo:public Animal{


public:
    Tuo(){
        cout<<"Tuo()"<<endl;
    }
    Tuo(int a):dataB(a)
    {
        cout<<"Tuo(int a)"<<endl;
    }
    ~Tuo(){
        cout<<"~Tuo()"<<endl;
    }
    void show(){
        cout<<"dataB value:"<<dataB<<"\t addr:"<<&dataB<<endl;
     }
    int dataB;
};




//羊驼类
//多继承 的时候 基类的构造函数执行的顺序 跟  继承的先后顺序有关
class SheepTuo:public Sheep,public Tuo
{
public:
    //在构造函数的参数列表中 指定 基类的构造函数
    SheepTuo(int a,int b):Tuo(b),Sheep(a)
    {
        cout<<"SheepTuo()"<<endl;
    }
    ~SheepTuo(){
        cout<<"~SheepTuo()"<<endl;
    }
    //在子类中重写 基类的同名函数,那么基类中的同名函数就会自动隐藏
    void show(){
        cout<<"dataA value:"<<dataA<<"\t addr:"<<&dataA<<endl;
        cout<<"dataB value:"<<dataB<<"\t addr:"<<&dataB<<endl;
        cout<<"dataC value:"<<dataC<<"\t addr:"<<&dataC<<endl;
       // cout<<"dataD value:"<<dataC<<"\t addr:"<<&dataD<<endl;
    }
    int dataC;
};




int main()
{
    //派生类对象的实例化
    SheepTuo mya(10,20);


    cout<<"mya size:"<<sizeof(mya)<<"\tmya addr:"<<&mya<<endl;


    mya.show();
    //发生二义性问题
    //mya.Animal::dataD = 100;
    //通过基类的类名显示调用
    //mya.Sheep::show();


    return 0;
}

分析:
使用qtcreator的断点调试可看到:
在这里插入图片描述
在这里插入图片描述
内存图如下:
在这里插入图片描述
通过分析可得, 创建B myb 对象的时候,构造函数顺序为 D---->A----->D—>C---->B

思考:如果myb访问D类中的成员,会发生什么情况??

答案: 会发生歧义,编译错误
在这里插入图片描述
如何解决:使用虚拟继承

四、虚拟继承(虚基类)

1、概念
为了解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题, 将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个 拷贝,同一个函数名也只有一个映射。这样不仅就解决了二义性问题,也节省了内存,避免了数据不一致的问题
2、格式

class  子类名称:virtual  父类名
{
};

3、例子

#include <iostream>

using namespace std;

//动物类
class Animal{
public:
    Animal(){
        cout<<"Animal()"<<endl;
    }
    Animal(int a):dataD(a)
    {
        cout<<"Animal(int a)"<<endl;
    }
    ~Animal(){
        cout<<"~Animal()"<<endl;
    }

    int dataD;
};

//羊类 --继承于 动物类  --虚基类  Animal
class Sheep:virtual public Animal{

public:
    Sheep(){
        cout<<"Sheep()"<<endl;
    }
    Sheep(int a):dataA(a)
    {
        cout<<"Sheep(int a)"<<endl;
    }
    ~Sheep(){
        cout<<"~Sheep()"<<endl;
    }
    void show(){
        cout<<"dataA value:"<<dataA<<"\t addr:"<<&dataA<<endl;
     }
    int dataA;
};

//驼类
class Tuo:virtual public Animal{

public:
    Tuo(){
        cout<<"Tuo()"<<endl;
    }
    Tuo(int a):dataB(a)
    {
        cout<<"Tuo(int a)"<<endl;
    }
    ~Tuo(){
        cout<<"~Tuo()"<<endl;
    }
    void show(){
        cout<<"dataB value:"<<dataB<<"\t addr:"<<&dataB<<endl;
     }
    int dataB;
};

//羊驼类
//多继承 的时候 基类的构造函数执行的顺序 跟  继承的先后顺序有关
class SheepTuo:public Sheep,public Tuo
{
public:
    //在构造函数的参数列表中 指定 基类的构造函数
    SheepTuo(int a,int b):Tuo(b),Sheep(a)
    {
        cout<<"SheepTuo()"<<endl;
    }
    ~SheepTuo(){
        cout<<"~SheepTuo()"<<endl;
    }
    //在子类中重写 基类的同名函数,那么基类中的同名函数就会自动隐藏
    void show(){
        cout<<"dataA value:"<<dataA<<"\t addr:"<<&dataA<<endl;
        cout<<"dataB value:"<<dataB<<"\t addr:"<<&dataB<<endl;
        cout<<"dataC value:"<<dataC<<"\t addr:"<<&dataC<<endl;
        cout<<"dataD value:"<<dataC<<"\t addr:"<<&dataD<<endl;
    }
    int dataC;
};

int main()
{
    //派生类对象的实例化
    SheepTuo mya(10,20);

    cout<<"mya size:"<<sizeof(mya)<<"\tmya addr:"<<&mya<<endl;

    mya.show();
    //发生二义性问题
    //mya.Animal::dataD = 100;
    //通过基类的类名显示调用
    //mya.Sheep::show();

    return 0;
}

现象:

A:virtual public D
C:virtual public D

在这里插入图片描述
分析:
在这里插入图片描述
总结:

  • 在多继承情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧跟其后的基类起作用。
  • 虚拟继承在创建对象的时候在子类对象中会有一个虚基类表指针,该虚基类表指针存储 虚基类 对象空间的最开始位置。
  • 类对象空间的大小 由 非静态成员数据+虚基类指针+字节对齐 组成。

五、虚函数、虚函数表

1、格式

virtual 函数返回类型 函数名(参数表) {函数体};

当一个类中有一个或多个虚拟函数,那么这个类在编译的时候就会创建一个虚函数表(简称虚表) 。虚表就是一个存放虚函数指针的表格,而这个表格的首地址存放在对象的地址开始位置。
2、例子

#include <iostream>


using namespace std;


class Data{
public:
    Data(){cout<<"Data()"<<endl;}
    ~Data(){cout<<"~Data()"<<endl;}


private:
    //在普通的函数前面加一个 关键字virtual ---虚函数
     virtual void setA(int val){
        cout<<"setA"<<endl;
        //dataA = val;
    }
     virtual void setB(int val){
        cout<<"setB"<<endl;
        //dataB = val;
    }
    virtual void setC(int val){
        cout<<"setC"<<endl;
        dataC = val;
    }
    int dataA;
    int dataB;
    int dataC;


private:


};




int main()
{
    Data mya;


    cout<<"mya size:"<<sizeof(mya)<<"mya addr:"<<&mya<<endl;


    //如何在类的外部 去调用类中的私有函数成员
    //可以将 私有函数成员 声明为 虚函数 ,通过虚表指针 去调用
    //mya.setA(10);
   // mya.setB(20);
   // mya.setC(30);

    //unsigned long 在window平台 是 4个字节  unsigned long long 是 8个字节
    //unsigned long 在linux平台  是 8个字节
    //求出虚表的地址
    unsigned long long *vptr =  (unsigned long long *)(*(unsigned long long*)&mya);
    cout<<"vptr:"<<vptr<<endl;


    cout<<"vptr+1:"<<vptr+1<<endl;

    return 0;
}

通过断点调试 可以看到在这里插入图片描述

3、注意:
1)、如果一个类中包含(一个或者多个)虚函数,那么这个类的对象中会包含一个虚表指针vptr
2)、虚表指针保存在对象内存空间的最前面
3)、虚表中存储的是 类中 虚函数的地址
4)、对象调用类中的虚函数,会查询虚表指针再去执行函数

4、虚表与虚表指针,虚基类表与虚基类表指针的区别
https://blog.csdn.net/qq_42719751/article/details/104656429

六、通过虚表指针调用虚函数

1、虚函数
在类的成员函数声明前面添加virtual,这个函数就被声明为虚函数, 那么这个类的对象中包含一个指向虚表的指针
2、虚表
存储虚函数地址
3、通过虚函数指针调用虚函数
在这里插入图片描述

#include <iostream>


using namespace std;


class Data{
public:
    Data(){}
    ~Data(){}




private:
    int a;


    //virtual关键字还可以用来修饰函数  ,称之为 虚函数
    virtual int test01(){
        cout<<__FUNCTION__<<endl;
    }
    virtual int test02(){
        cout<<__FUNCTION__<<endl;
    }
    int test03(){
        cout<<__FUNCTION__<<endl;
    }
};




int main()
{
    Data d1;


    //d1.test01();
    //d1.test02();


    cout<<"size:"<<sizeof(Data)<<endl;


    //通过得到虚表中的函数的地址去调用函数
    //如果该函数是私有权限下的函数,能够突破类中权限的限制
    //1)先获取虚表的地址
    //*(unsigned long long*)&d1;  地址常量 0x100ff1a
    unsigned long long*vptr = (unsigned long long*)*(unsigned long long*)&d1;


    cout<<"vptr:"<<vptr<<endl;


    //求test01函数的地址
    //*vptr 等价于vptr[0]  --得到test01函数的地址--但是该地址是一个常量,必须转换成函数类型的地址
    typedef  int (*PFunc_t)(void);
//    PFunc_t test01_p = (PFunc_t)vptr[0];
//    test01_p();
    ((PFunc_t)vptr[0])();

//    PFunc_t test02_p = (PFunc_t)vptr[1];
//    test02_p();

    return 0;
}

4、总结

  • 同一个类的不同实例共用同一份虚函数表, 它们都通过一个所谓的虚函数表指针__vfptr指向该虚函数表.
  • 虚表存储在进程的数据段.rodata中,虚函数存储在代码段中的.text段中
  • 当类中有虚函数的时候,编译器在编译的时候就会为该类创建一张虚表,而且只存在一份。定义类对象时, 编译器自动将类对象的__vfptr指向这个虚函数表。
  • 通过虚函数表能够突破虚函数访问权限的控制。比如我们可以将虚函数定义为private类型,这样在类外面就不能通过对象调用private类型的函数了。但是在类的虚函数表中,不论其访问类型是public还是private的,其所有虚函数都会存放其中。

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

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

相关文章

(补充):java各种进制和文本、图像、音频在计算机中的存储方式

文章目录 前言一、进制1 逢几进一2 常见进制在java中的表示3 进制中的转换(1)任意进制转十进制(2)十进制转其他进制二、计算机中的存储1 计算机的存储规则(文本数据)(1)ASCII码表(2)编码规则的发展演化2 计算机的存储规则(图片数据)(1)分辨率、像素(2)黑白图与灰度…

线程池【开发实践】

文章目录 一、为什么要用线程池1.1 单线程的问题1.2 手动创建多线程的问题1.3 线程池的作用&#xff08;优点&#xff09;1.4 线程池的使用场景 二、线程池的基础知识2.1 线程池的核心组件2.2 JUC中的线程池架构2.3 线程池的配置参数2.4 线程池常见的拒绝策略&#xff08;可自定…

el-image放大图片功能

1.需求&#xff1a;点击图片后放大图片 html代码&#xff1a; <el-imagestyle"width: 100px; height: 100px":src"baseUrl item.id":zoom-rate"1.2":max-scale"7":min-scale"0.2":preview-src-list"srcList"…

淘宝商品历史价格查询(免费)

当前资料来源于网络&#xff0c;禁止用于商用&#xff0c;仅限于学习。 淘宝联盟里面就可以看到历史价格 并且没有加密 淘宝商品历史价格查询可以通过以下步骤进行&#xff1a; 先下载后&#xff0c;登录app注册账户 打开淘宝网站或淘宝手机App。在搜索框中输入你想要查询的商…

Iptables与Firewalld防火墙

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 目录 一、防火墙管理工具 二、Iptables 三、Firewalld ​四、服务的访问控制列表 五、Cockpit驾驶舱管理工具 致谢 一、防火墙管理工具 防火墙…

js ES6 part1

听了介绍感觉就是把js在oop的使用 作用域 作用域&#xff08;scope&#xff09;规定了变量能够被访问的“范围”&#xff0c;离开了这个“范围”变量便不能被访问&#xff0c; 作用域分为&#xff1a; 局部作用域、 全局作用域 1. 函数作用域&#xff1a; 在函数内部声明的…

【UE5】仅修改结构体的若干个数据

蓝图中的结构体变量 | 虚幻引擎4.27文档 (unrealengine.com) 连线连到傻&#xff0c;因为如果某个变量set空值也一起过去了。一查发现有这个节点。

Windows10系统下mysql5.6的安装步骤

1.下载mysql 下载地址&#xff1a;https://downloads.mysql.com/archives/community/ 在这里我们下载zip的包 2.解压mysql包到指定目录 3. 添加my.ini文件 # For advice on how to change settings please see # http://dev.mysql.com/doc/refman/5.6/en/server-configurat…

最新深度技术Win7精简版系统:免费下载!

在Win7电脑操作中&#xff0c;用户想要给电脑安装上深度技术Win7精简版系统&#xff0c;但不知道去哪里才能找到该系统版本&#xff1f;接下来系统之家小编给大家带来了深度技术Win7系统精简版本的下载地址&#xff0c;方便大家点击下载安装。系统安装步骤已简化&#xff0c;新…

Java客户端调用SOAP方式的WebService服务实现方式分析

简介 在多系统交互中&#xff0c;有时候需要以Java作为客户端来调用SOAP方式的WebService服务&#xff0c;本文通过分析不同的调用方式&#xff0c;以Demo的形式&#xff0c;帮助读者在生产实践中选择合适的调用方式。 本文JDK环境为JDK17。 结论 推荐使用Axis2或者Jaxws&#…

20240709每日后端--------最优解决Invalid bound statement (not found)

目标 最优解决Invalid bound statement (not found) 步骤 1、打包 2、查看target下是否成双成对出现 3、核对无误后&#xff0c;即可解决问题。

重塑智慧生活想象 Yeelight易来举行2024年战略及新品发布会圆满成功

7月9日&#xff0c;智能照明品牌Yeelight易来在广州举行“光为境和无界”——2024年Yeelight易来战略&新品发布会&#xff0c;此次发布会不仅展示了易来在新的一年中取得的显著业绩增长&#xff0c;还发布了多款引领行业潮流的智能新品。同时&#xff0c;发布会还邀请了权威…

Docker搭建kafka+zookeeper以及Springboot集成kafka快速入门

参考文章 【Docker安装部署KafkaZookeeper详细教程】_linux arm docker安装kafka-CSDN博客 Docker搭建kafkazookeeper 打开我们的docker的镜像源配置 vim /etc/docker/daemon.json 配置 { "registry-mirrors": ["https://widlhm9p.mirror.aliyuncs.com"…

mysql查询语句执行流程

流程图 连接器&#xff1a;建立连接&#xff0c;管理连接、校验用户身份&#xff1b;查询缓存&#xff1a;查询语句如果命中查询缓存则直接返回&#xff0c;否则继续往下执行。MySQL 8.0 已删除该模块&#xff1b;解析 SQL&#xff0c;通过解析器对 SQL 查询语句进行词法分析、…

构造二进制字符串

目录 LeetCode3221 生成不含相邻零的二进制字符串 #include <iostream> #include <vector> using namespace std;void dfs(string s,int n,vector<string>& res){if(s.size()n){res.push_back(s);return;}dfs(s"0",n,res);dfs(s"1"…

Zabbix Sia Zabbix 逻辑漏洞(CVE-2022-23134)

前言 CVE-2022-23134是一个中等严重度的漏洞&#xff0c;影响Zabbix Web前端。这个漏洞允许未经身份验证的用户访问setup.php文件的某些步骤&#xff0c;这些步骤通常只对超级管理员开放。利用这个漏洞&#xff0c;攻击者可以通过跳过某些步骤来重新配置Zabbix前端&#xff0c…

代码随想录算法训练营第四十八天| 115.不同的子序列、583. 两个字符串的删除操作、 72. 编辑距离

115.不同的子序列 题目链接&#xff1a;115.不同的子序列 文档讲解&#xff1a;代码随想录 状态&#xff1a;不会 思路&#xff1a; dp[i][j] 表示在 s 的前 j 个字符中&#xff0c;t 的前 i 个字符作为子序列出现的次数。 匹配的情况&#xff1a; 1.当 s[j-1] 与 t[i-1] 匹配…

软考高级里《系统架构设计师》容易考吗?

我还是22年通过的架构考试。系统架构设计师属于软考高级科目&#xff0c;难度比初级和中级都要大&#xff0c;往年的通过率也比较低&#xff0c;一般在10-20%左右。从总体来说&#xff0c;这门科目确实是不好过的&#xff0c;大家如果想要备考系统架构设计师的话&#xff0c;还…

营销宝典:4P理论全方位解读,营销人的必修课

这么说吧&#xff0c;4P是营销的一切&#xff0c;也是一切的营销&#xff01; 4P理论产生于20世纪60年代的美国&#xff0c;随着营销组合理论的提出而出现的。 1953年&#xff0c;尼尔博登&#xff08;NeilBorden&#xff09;在美国市场营销学会的就职演说中创造了“市场营销…

【Python】已解决:SyntaxError: invalid character in identifier

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;SyntaxError: invalid character in identifier 一、分析问题背景 在Python编程中&#xff0c;SyntaxError: invalid character in identifier是一个常见的编译…