数据结构预备知识(四)

本文详细介绍了类的简单继承和多重继承的概念,包括派生类的定义、基类成员的访问规则、构造函数的调用顺序等内容,并探讨了多态性和虚函数的应用。

类的继承

简单继承
多重继承
多态性和虚函数


简单继承
1.派生类的定义
2.基类成员的引用和访问的规则
3.导出类的构造函数
4. 覆盖  作用域分辨
5.派生类的类型转换
6. 导出类的指针
简单继承
    从一个类可以派生出新的类——派生类或导出类,也叫子类.
    原来的类叫基类也叫父类.


1.派生类的定义形式
  class 新类名:public  基类名    //公有继承
       {·········};
  class 新类名:private  基类名   //私有继承       
       {·········};
 
//缺省为私有继承,
//基类是struct类时缺省是公有继承

基类中的成员自动成为导出类的成员。

基类限制词:public和private指明基类成员在导出类中的访问限制
例:class roadVehicle
          {       int wheels, passengers;
             public:
                    roadVehicle(int, int);
    void SetWheels(int num);
    void SetPassengers(int num);
  int GetWheels(void);
  int GetPassengers(void);
                     void print( )
                      {cout<<“\nwheels=”<<wheels
                        <<“\nPassengers=”<<passengers;
                         }
             };
       
class truck : public roadVehicle
{   int cargo;
   public:
     truck(int,int,int);
     void SetCargo(int size);
     int GetCargo(void);
     void Show(void);
     void print( );
   };     

Truck类有三个数据成员:
 wheels,passengers
cargo.
有9个成员函数

不继承的部分
1。构造函数和析构函数
2。重载的操作符和赋值符
3。友元

基类中同名的成员被派生类中相应的名字覆盖
           
2.基类成员的引用和访问的规则

  class A

class B : public A

class C : public B

  private

      不可见

       不可见

protected

     protected

      protected

  public

       public

        public


 class A

class B : private A

class C : private B

 private  

        不可见

不可见

protected

         private

不可见        

 public   

         private

不可见


保护成员protected数据在基类中同private


公有基类的保护成员和公有成员是导出类的保护和公有成员
私有基类的保护成员和公有成员是导出类私有成员
基类的私有成员在导出类中不可见只能通过基类的公有成员函数调用
例   void truck::print(void)
      { cout<<“\nwheels=”<<wheels   //出错
          <<“\npassengers=”<<passengers  //出错
           <<“\ncargo=”<<cargo;}

应改为
   void truck::print(void)
      { roadVehicle::print( );
          cout <<“\ncargo=”<<cargo; }

3.导出类的构造函数
派生类不继承构造函数和析构函数
派生类的构造函数必须包含基类构造函数的信息
要为基类构造函数提供初始化参数
class truck 的构造函数:


truck::truck(int a,int b,int c) : roadVahicle(a,b)

如果 roadVehicle类中
         roadVehicle::roadVehicle(int x,int y)
               {wheels=x;  passengers=y;}


则truck类中
    truck::truck(int a, int b, int c) : roadVehicle(a,b)
      {  cargo=c;  }
              
注意:
导出类的构造函数中未写明基类构造函数
基类构造函数的参数无法传递,
这时导出类自动调用基类的无参构造函数,
如果基类没有无参构造函数,就会出错。

如果派生类中还有基类的对象成员
class truck : public roadVehicle
 {   int cargo;
      roadVehicle a;
  public:
     truck(int,int,int,int,int);
     truck(int x):roadVehicle(x,x+1),a(x,x){ cargo=x;  }
     void SetCargo(int size);
     int GetCargo(void);
     void Show(void);
     void print( );
   }; 

例  truck类的构造函数
truck::truck(int a1, int a2, int b1, int b2, int c) : roadVehicle(a1,a2), a(b1,b2)
      {  cargo=c;  }

基类的构造函数由基类名标出
对象成员的构造函数由对象名标出

构造函数的调用顺序
先基类再导出类
析构函数相反

4. 覆盖  作用域分辨
基类中同名的成员被派生类中相应的名字覆盖


例  class A
      {    ······
          public:
             ······ 
            int fun( )
            {return 1;}
        }


class B : public A
  { ······
      public:
     ······ 
       int fun( )//覆盖A中同名元
       {return 2;}
  }

A a;  B b;    int i=a.fun( );  // i=1  
         int j=b.fun( );  // j=2
          i=b.A::fun( );  // i=1 作用域分辨



class B : public A
      {    ······
          public:
             ······ 
            int fun( ){return 2;}
            int f( ){return A::fun( );}
        }

B b;   int i=b.fun( );  //i=2
          int j=b.f( );  //i=1

例  truck类中的print函数

   void truck::print(void)
      { roadVehicle::print( );
          cout <<“\ncargo=”<<cargo; }


    truck   t(4,3,4);
    t.print( );
                      输出:  wheels=4
                                    passengers=3
                                    cargo=4   
5.派生类的类型转换
class A
{······};
class B : public A
 {······};
B是A的派生类,
B是A的超集
可以将类B的对象自动转换
为A类对象,反之不成立.
A a; B b;
A *ap=new A;
B *bp=new B;
a=b;      //正确
ap=bp;  //正确
b=a;      //错误
bp=ap;  //错误

用户定义类型转换
类型转换函数重载
   X::operator T( );
X是原定义类型,T是转换后类型。
不带参数,没有返回类型。T就是返回类型。


例  String::operator char *(void )
      {return str;}
operator char *(void )是String类的成员函数
String类对象可以作char*字符串类型使用。

X::operator T( );
  X类对象可以作T类型使用
   X  s;
   T  a=s; //隐式转换 用于初始化
   T fun( T t);
   a=fun(s); //隐式转换 用于函数参数
   X f( X t);
    a=f(s);  //隐式转换 用于函数返回值
   
隐式类型转换的规则:
 用于初始化,函数参数,函数返回值
  1.标准转换优先(转换成标准类型)。
  2.不允许转换再转换
  3.必须唯一确定,不能有二义性。


不能用隐式类型转换时用强制类型转换
    a= T(s); //显式转换 强制类型转换
6. 导出类的指针
1 公有基类
   指向导出类对象的指针可以隐式转换为指向基类对象的指针 反之不成立
 class A
  {······};
class B : public A
  {······};

A *ap=new A;
B *bp=new B;
ap=bp;  //正确
bp=ap;  //错误
bp=(B*)ap;//正确,
                 //显式转换
2.私有基类——不能隐式转换
多重继承
1.多重继承的定义 由多个基类派生出一个类
class A;
class B;
class C :public A, public B
{······}; 
每个基类都应有自己的存定符
A,B的成员都自动成为C的成员,存取权限同单继承

2.构造函数
导出类的构造函数要为基类提供初始化参数
方法与单继承相同。
调用时先基类再导出类。基类的次序从左到右。


C::C(int a, int b, int c):A(a),B(b)
     {······}

3. 二义性和覆盖
    两个基类中有同名成员都被继承。导出类对象调用时出现二义性,要用类名域加以区别。
    也可以在导出类中定义一个同名成员加以覆盖,消除二义性。
class A
{ public:
   void f( ); };  

class B
{ public:
   void f( ); };  

class C : public A, public B
{ public:
      ······      };  

C  c;
c.f( ); //二义性  A的f, B的f ?
c.A::f( ); //合法
c.B::f( ); //合法

class C : public A, public B
{ public:
      ······      };  
void f( ){A::f( );
               B::f( );  }   };
C  c;
c.f( ); //二义性  A的f, B的f ?
c.A::f( ); //合法
c.B::f( ); //合法

4.虚基类
    一个基类被派生出两个以上导出类,这两个导出类再生成一个多重导出类.
    在导出类D中, A的一个元素通过两个途径被继承了两次。这种情况叫双重继承。
   虚基类定义可以避免双重继承
class A;
class B : virtual public A;
class C : virtual public A;
Class D : public B, public C;
这样定义的D类中A的成员只继承一次,可以直接访问A的成员,也可以用任意路径访问。

   基类的所有直接导出类中都要用virtual声明为虚基类,否则仍然是多重继承。

构造函数的调用次序
先虚基类(依声明次序从左到右)
后非虚基类(依声明次序)

多态性和虚函数
1.多态性
    不同的对象调用同一个函数
    导致不同的操作称为多态性


    运算符重载和函数重载
    是最简单的多态性
1.动态联编
程序在编译时决定由某对象对实例发出的消息,翻译并完成所要求的操作,叫前期装配,或早联编(early binding),也叫静态联编。
程序在编译时不确定由某对象对实例发出的消息,而是在运行过程中确定由哪个对象实例发出的消息,翻译并完成所要求的操作,叫后期装配,或后联编(later binding),也叫动态联编。

虚函数的用法
1. 动态联编只能在基类和派生类中有同名同参的函数才能使用。同名不同参不能覆盖。

2.只要在基类成员函数(公共或保护部分)使用  virtual ,中间类同名同参的函数自然也是虚函数

3.如果调用函数为show(B*t)时,中间类也要声明
   virtual函数
4.如果派生类要通过虚函数机制存取虚函数,必须建立一条基类到派生类的虚函数路径。即每个中间类都必须有同名同参的函数。

5.如果某个中间类不需要这样的函数,而其后的派生类需要这个虚函数。可以在中间类中声明一个同名同参的空虚函数。 

virtual print( ){ }

任何对象都不能调用空虚函数
私有函数也可以声明为虚函数

不能将全局函数或静态函数声明为虚函数
全局函数,静态函数与对象无关。

构造函数不能声明为虚函数

构造函数可以调用虚函数

小心:构造函数中基类构造函数优先
如果基类构造函数调用虚函数,
则必定调用了基类中的虚函数
而派生类中的构造函数则调用派生类中的虚函数,如果派生类中没有这个虚函数则调用基类中的虚函数。

2.纯虚函数
类等级的顶层可以将所有公共函数都声明为纯虚函数。这就可以使每个公用函数都成为后联编实现动态多样性。这样的类不需要任何操作,也不必实例化,即不用定义对象。
纯虚函数的声明
      virtual int f( )=0; //表示这个函数没有定义

抽象类
至少有一个纯虚函数的类是一个抽象类。
抽象类不能定义对象,但可以定义指针
指向它。
抽象类的派生类必须覆盖基类中所有纯虚函数,否则纯虚函数被继承,使派生类仍然是抽象类,而不能定义对象。
抽象基类相当于派生类的模板,它的数据和方法可以被所有派生类共享

一个类的虚函数可以定义为另一个
类的友元。


友元函数不能是虚函数。


运算符可以定义为虚函数。
析构函数也可以定义为虚函数。

何时要用虚函数
1.类顶或其附近的类中。
2.函数的性质依赖于类的结构或类型。
3.实现类的输入或输出操作的函数。
4.函数的操作是为专门的类而定义的。

如何使多态性失效
  用作用域分辨符分辨操作符,就可以使多态性失效。
派生类中的虚函数可以调用基类中的同名虚函数,只要使用作用域分辩符,指明调用基类函数,就不会引起无穷循环。

异质链表
   #include "iostream.h"
   #include "string.h"
   #include "stdio.h"
  #include "stdlib.h"

   class list;
本文旨在系统阐述利用MATLAB平台执行多模态语音分离任务的方法,重点围绕LRS3数据集的数据生成流程展开。LRS3(长时RGB+音频语音数据集)作为一个规模庞大的视频与音频集合,整合了丰富的视觉与听觉信息,适用于语音识别、语音分离及情感分析等多种研究场景。MATLAB凭借其高效的数值计算能力与完备的编程环境,成为处理此多模态任务的适宜工具。 多模态语音分离的核心在于综合利用视觉与听觉等多种输入信息来解析语音信号。具体而言,该任务的目标是从混合音频中分离出不同说话人的声音,并借助视频中的唇部运动信息作为辅助线索。LRS3数据集包含大量同步的视频与音频片段,提供RGB视频、单声道音频及对应的文本转录,为多模态语音处理算法的开发与评估提供了重要平台。其高质量与大容量使其成为该领域的关键资源。 在相关资源包中,主要包含以下两部分内容: 1. 说明文档:该文件详细阐述了项目的整体结构、代码运行方式、预期结果以及可能遇到的问题与解决方案。在进行数据处理模型训练前,仔细阅读此文档对正确理解与操作代码至关重要。 2. 专用于语音分离任务的LRS3数据集版本:解压后可获得原始的视频、音频及转录文件,这些数据将由MATLAB脚本读取并用于生成后续训练与测试所需的数据。 基于MATLAB的多模态语音分离通常遵循以下步骤: 1. 数据预处理:从LRS3数据集中提取每段视频的音频特征与视觉特征。音频特征可包括梅尔频率倒谱系数、感知线性预测系数等;视觉特征则涉及唇部运动的检测与关键点定位。 2. 特征融合:将提取的音频特征与视觉特征相结合,构建多模态表示。融合方式可采用简单拼接、加权融合基于深度学习模型的复杂方法。 3. 模型构建:设计并实现用于语音分离的模型。传统方法可采用自适应滤波器矩阵分解,而深度学习方法如U-Net、Transformer等在多模态学习中表现优异。 4. 训练与优化:使用预处理后的数据对模型进行训练,并通过交叉验证与超参数调整来优化模型性能。 5. 评估与应用:采用信号失真比、信号干扰比及信号伪影比等标准指标评估模型性能。若结果满足要求,该模型可进一步应用于实际语音分离任务。 借助MATLAB强大的矩阵运算功能与信号处理工具箱,上述步骤得以有效实施。需注意的是,多模态任务常需大量计算资源,处理大规模数据集时可能需要对代码进行优化借助GPU加速。所提供的MATLAB脚本为多模态语音分离研究奠定了基础,通过深入理解与运用这些脚本,研究者可更扎实地掌握语音分离的原理,从而提升其在实用场景中的性能表现。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值