栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

(C++笔记)第二十三节课:继承与多态

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

(C++笔记)第二十三节课:继承与多态

# 一 继承 ## 1.1 继承中的类型兼容性原则


概念:类型兼容性原则是指在需要基类对象的地方,我们都可以直接使用公有派生类对象,通过公有继承,我们可以得到基类中除了构造函数,析构函数外的所有成员,这样,凡是基类可以解决的问题,派生类都可以解决。

(1)子类对象可以当成父类对象使用,子类对象是一种特殊的父类。
(2)父类指针可以直接指向子类对象
(3)父类引用可以直接引用派生类对象
 


#include
using namespace std;
class Parent
{
    protected:
        int m_a;
        int m_b;
    public:
        Parent()
        {
            cout<<"Parent的无参构造函数"<         }
        Parent(const Parent &obj)
        {
            cout<<"Parent的拷贝构造函数"<             m_a = obj.m_a;
            m_b = obj.m_b;
        }
        void SetAB(int a,int b)
        {
            m_a = a;
            m_b = b;
        }
        void print()
        {
            cout<<"m_a = "<m_a<             cout<<"m_b = "<m_b<         }
};
class Child:public Parent
{
private:
    int m_c;
public:
    void SetC(int c)
    {
        this->m_c = c;
    }
    void printC()
    {
        cout<<"c = "<     }
};
int main(int argc, char const *argv[])
{
   
    Child c;
    c.SetAB(10,20);
    c.SetC(30);
    c.print();
    c.printC();

    //Child *pc = &c;
    //Parent *p = &c;
    //p->SetAB(1,2);
    //p->SetC(20);

    Parent &p = c;
    p.printC();
    return 0;
}

## 1.2 多继承 ### (1) 概念


派生类中如果只有一个基类,称为单继承,除此之外,c++中还支持多继承,每一个派生类可以继承多个基类。
 

(2)多继承的语法


用逗号将继承的基类隔开。

#include
using namespace std;
class AirPlane
{
    protected:
        int high;
    public:
        AirPlane()
        {
            cout<<"飞机的构造函数"<             high = 100;
        }
        void show()
        {
            cout<<"飞机的高度:"<         }
};
class Ship
{
    protected:
        int speed;
    public:
        Ship()
        {
            cout<<"轮船的构造函数"<             speed = 40;
        }
        void show()
        {
            cout<<"航行的速度:"<         }
};
class WaterPlane:public Ship,public AirPlane
{
    public:
        WaterPlane()
        {
            cout<<"水上飞机的构造函数"<         }
};
int main(int argc, char const *argv[])
{
    WaterPlane w;
    cout<     w.AirPlane::show();
    w.Ship::show();
    return 0;
}

### (2)多继承的构造和析构


#include
using namespace std;
class AirPlane
{
    protected:
        int high;
    public:
        AirPlane(int h):high(h)
        {
            cout<<"飞机的构造函数"<         }

        ~AirPlane()
        {
            cout<<"Airplane的析构函数"<         }
};
class Ship
{
    protected:
        int speed;
    public:
        Ship(int s):speed(s)
        {
            cout<<"轮船的构造函数"<         }
        ~Ship()
        {
            cout<<"ship的析构函数"<         }

};
class WaterPlane:public Ship,public AirPlane
{
    public:
        WaterPlane(int h,int s):AirPlane(h),Ship(s)
        {
            cout<<"水上飞机的构造函数"<         }
        ~WaterPlane()
        {
            cout<<"水上飞机的析构函数"<         }
};
int main(int argc, char const *argv[])
{
    WaterPlane w(100,40);
    return 0;
}
 

### (3)多继承的二义性


#include
using namespace std;
class TestA
{
    public:
        int a[7];
};
class TestB:public TestA
{
    public:
        int b;
};
class TestC:public TestA
{
    public:
        int c;
};
class TestD:public TestB,public TestC
{
    public:
        int d;
};
int main(int argc, char const *argv[])
{
    TestD td;
    cout<     td.a;
    return 0;
}
 

 

### (4)虚继承


虚继承的目的是为了让某个类作出声明,承若愿意共享它的基类,这个被共享的基类称为虚基类,在这种情况下,无论虚基类在继承体系中出现多少次,在派生类中只会为其开辟一次内存空间

#include
using namespace std;
class TestA   //虚基类
{
    public:
        int a;
};
class TestB:virtual public TestA
{
    public:
        int b;
};
class TestC:virtual public TestA
{
    public:
        int c;
};
class TestD: public TestB, public TestC
{
    public:
        int d;
};
int main(int argc, char const *argv[])
{
   
    TestB tb;
    cout<     cout<<&tb<     cout<<&tb.a<     cout<<&tb.b<

    TestD td;
    cout<     cout<<&td<     cout<<&td.a<     cout<<&td.b<     cout<<&td.c<     cout<<&td.d<

    return 0;
}

### (5) 向上转型


#include
using namespace std;
class Parent
{
    private:
        int m_a;
};
class Child:public Parent
{
    private:
        int m_b;
};
int main(int argc, char const *argv[])
{
    int a = 1.11;
    double b = 2;
    //printf("a = %pn",&a);
    //printf("a = %#xn",&a);

    Parent p;
    Child c;
    //c = p;
    p = c;  //只能将派生类对象赋值给基类对象,派生引用赋值给基类引用,派生类指针赋值给基类指针
    return 0;
}

# 二 多态 ## 2.1 问题


#include
using namespace std;
class Parent
{
    public:
        void show()
        {
            cout<<"this is Parent"<         }
};
class Child:public Parent
{
    public:
        void show()
        {
            cout<<"this is child"<         }
};
int main(int argc, char const *argv[])
{
    Parent *p1 = new Child;  //静态联编,编译器会p1的类型,调用parent里面的show函数
    p1->show();
    return 0;
}

## 2.2 多态的概念和使用


多态:多种形态,使用多态,当基类指针指向基类对象的时候,期待其按照基类的方法做事,当基类指针指向派生类对象的时候,就按照派生类的方法做事,实现同一个接口,多种方法,它有多种形态,这种现象称为多态。


多态的条件:


1.要有继承
2.要有虚函数重写(发生在不同的作用域,函数原型相同)
3.基类指针指向派生类对象

#include
using namespace std;
class Parent
{
    public:
        virtual void show()
        {
            cout<<"this is Parent"<         }
};
class Child:public Parent  //1.要有继承
{
    public:
        void show()    //2.要有虚函数重写
        {
            cout<<"this is child"<         }
};
int main(int argc, char const *argv[])
{
    Parent *p1 = new Child;  //3.基类指针指向不同的对象
    p1->show();
    delete p1;
    p1 = new Parent;
    p1->show();
    delete p1;
    return 0;
}
 

## 2.3 多态的原理


#include
using namespace std;
class Parent
{
    public:
        int a;
        virtual void show()
        {
            cout<<"this is Parent"<         }
};
class Child:public Parent  //1.要有继承
{
    public:
        void show()    //2.要有虚函数重写
        {
            cout<<"this is child"<         }
};
int main(int argc, char const *argv[])
{
    Parent p;
    Child c;
    cout<     cout<     cout<<"Parent的起始地址:"<<&p<     cout<<"成员变量a的起始地址:"<<&p.a<     return 0;
}

 

## 2.4 虚析构函数


根据析构的规则,只能从当前基类开始往上析构,而并不能调用到派生类中的析构函数,通过将基类的析构函数设置成虚函数,调用delete后,使其可以按照正确的顺序析构动态创建的对象。

#include
using namespace std;
class Parent
{
    public:
        int a;
        virtual void show()
        {
            cout<<"this is Parent"<         }
        Parent()
        {
            cout<<"Parent的构造函数"<         }
        virtual ~Parent()
        {
            cout<<"Parent的析构函数"<         }
};
class Child:public Parent  //1.要有继承
{
    public:
        void show()    //2.要有虚函数重写
        {
            cout<<"this is child"<         }
        Child()
        {
            cout<<"Child的构造函数"<         }
        ~Child()
        {
            cout<<"child的析构函数"<         }
};
int main(int argc, char const *argv[])
{
    Parent *p = new Child;
    delete p;
    return 0;
}
```

## 2.5 动态类型识别
dynamic_cast


1.dynamic_cast是c++新型关键词
2.dynamic_cast用于基类和派生类之间的转换
3.dynamic_cast要求使用的目标类型是多态的。
   即要求所在类中至少有一个虚函数。
   用于指针转换时,转换失败会返回NULL指针。
   用于引用转换时,转换失败会引发bad_cast异常。


优势:


1.    不需要显示的声明和定义虚函数
2.  不用为每个类分配类型ID
缺点:
1.只能用于有虚函数的类
```


#include
using namespace std;
class Parent
{
    private:
        int m_a;
    public:
        enum{ID = 0};
        virtual int GetId()
        {
            return ID;
        }
};
class Child:public Parent
{
    public:
        int array[102400];
        enum{ID = 1};
        virtual int GetId()
        {
            return ID;
        }
};
void func(Parent *p)
{
    //Child *c = (Child *)p;
    if(p->GetId() == Child::ID)
    {
        Child *c = (Child *)p;
        c->array[102400 -1] = 100;
        cout<<"转换成功"<     }
    else
    {
        cout<<"转换失败"<     }
    
}
int main(int argc, char const *argv[])
{
    Parent *p = new Child;
    //Parent *p = new Parent;
    func(p);
    return 0;
}

## 2.6 dynamic_cast


#include
using namespace std;
class Parent
{
    private:
        int m_a;
    public:
        virtual void show(){}
};
class Child:public Parent
{
    public:
        int array[102400];
    public:
        virtual void show(){}
};
void func(Parent *p)
{
    Child *c  = dynamic_cast(p);   //如果p指向的是基类对象,则转换失败,转换失败返回NULL
    if(NULL == c)
    {
        cout<<"转换失败"<     }
    else
    {
        c->array[102400 -1] = 100;
        cout<<"转换成功"<     }
}
int main(int argc, char const *argv[])
{
    Parent *p = new Child;
    //Parent *p = new Parent;
    func(p);
    return 0;
}

## 2.7 typeid


typeid可以用于获取一个表达式的类型信息
typeid的操作对象既可以是表达式,也可以是数据类型
    typeid(dataType);
或者:
    typeid(expression);


#include
#include
using namespace std;
class Parent
{
    private:
        int m_a;
    public:
        virtual void show(){}
};
class Child:public Parent
{
    public:
        int array[102400];
    public:
        virtual void show(){}
};
void func(Parent *p)
{
    if(typeid(*p) == typeid(Child))
    {
        Child *c = (Child *)p;
        c->array[102400 -1] = 100;
        cout<<"转换成功"<     }
    else if(typeid(*p) == typeid(Parent))
    {
        cout<<"转换失败"<     }
}
int main(int argc, char const *argv[])
{
    int a;
    char ch;
    Parent p1;
    Child c1;
    const type_info &pa = typeid(a);
    const type_info &pch = typeid(ch);
    const type_info &pp1 = typeid(p1);
    const type_info &pc1 = typeid(c1);
    cout<     cout<     cout<     cout<     Parent *p = new Child;
    //Parent *p = new Parent;
    func(p);
    return 0;
}
 

## 2.8 纯虚函数


virtual 返回值类型 函数名 (函数形参)= 0;

#include
using namespace std;
class Parent   //含有纯虚函数的类称为抽象类,抽象类不能实例化对象
{
    public:
        virtual void show() = 0;  //纯虚函数,没有函数体
};
class Child:public Parent
{
    public:
        virtual void show()
        {
            cout<<"this is child"<         }
};
int main(int argc, char const *argv[])
{
    Parent *p = new Child;
    p->show();
    return 0;
}
 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1009252.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号