C++(7)多态

多态  polymorphism 

1、父类中有虚函数

2、子类中覆写(override)父类的虚函数

3、子类对象的地址赋给了父类的指针,并通过该指针用虚函数

#include <iostream>

using namespace std;

class A
{
public:
    virtual void func()
        cout<<"class A"<<endl;
};

class B
{
private:
    void func()
        cout<<"class B"<<endl;
};

int main()
{
    A *pa = new B;  // 输出class B
    pa->func();

    return 0;
}

赋值兼容只发生在公有派生的父子关系

子类对象赋给父类的对象

子类对象赋给父类的引用

子类对象的地址赋给父类的指针 

#include <iostream>

using namespace std;

class Shape
{
public:
    Shape(int x, int y)
        :_x(x), _y(y)
    {}
    
    void draw()
    {
        cout<<"draw from "<<"("<<_x<<","<<_y<<")"<<endl; 
    }

protected:
    int _x;
    int _y;
};

class Circle:public Shape
{
public:
    Circle(int x, int y, int r)
        :Shape(x, y), _radius(r)
    {} 

    void draw()
    {
        cout<<"draw from "<<"("<<_x<<","<<_y<<")"<<endl; 
        cout<<"radius = "<<_radius<<endl;
    }
    
private:
    int _radius;
};

int main()
{
    Shape s(1, 2);
    s.draw();

    Circle c(3, 4, 5);
    c.draw();
    c.func();

    s = c;
    s.draw();

    return 0;
}

静多态:编译阶段决定的

动多态:在运行时决定的

发生多态

1、父类中有虚函数,声明虚函数virtual

扫描二维码关注公众号,回复: 16354117 查看本文章

2、子类中覆写(override)了父类的虚函数

3、将子类对象地址赋值给父类的指针,并发生虚函数的调用

#include <iostream>

using namespace std;

class Shape
{
public:
    Shape(int x, int y)
        :_x(x), _y(y)
    {}
    
    virtual void draw();

protected:
    int _x;
    int _y;
};

class Circle:public Shape
{
public:
    Circle(int x, int y, int r)
        :Shape(x, y), _radius(r)
    {} 

    virtual void draw()
    {
        cout<<"draw from "<<"("<<_x<<","<<_y<<")"<<endl; 
        cout<<"radius = "<<_radius<<endl;
    }
    
private:
    int _radius;
};

void Shape::draw
{
    cout<<"draw from "<<"("<<_x<<","<<_y<<")"<<endl; 
}

class Rect:public Shape
{
public:
    Rect(int x, int y, int len, int wid)
        :Shape(x, y), _len(len), _wid(wid)
    {}

    virtual void draw()
    {
        cout<<"start from "<<"("<<x<<","<<y<<")"<<endl;
        cout<<" len = "<<_len<<" wid = "<<_wid<<endl;
    }

private:
    int _len;
    int _wid;
};

int main()
{
    Circle c(3, 4, 5);
    c.draw();

    Shape *ps;

    //Shape *p = &c;
    // p->draw();

    // p = new Rect(3, 4, 5, 6);
    // p->draw();

    int choice;
    while(1)
    {
        scanf("%d", &choice);

        switch(choice)
        {
            case 1:
                ps = &c;
                ps->draw();
                break;
            case 2:
                ps = &r;
                ps->draw();
                break;
        }
    }
    
    return 0;
}

声明虚函数的方法 virtual void func();  声明型关键字

覆写override

overload 重载:同一作用域,函数名相同,参数列表不同

shadow         :发生在父子类中的同名成员

override         : 发生在父子类中,父类中函数有virtual声明的函数

子类中,同参数、同名称、同返回函数之间构成覆写

纯虚函数

格式: virtual void draw() = 0;

纯虚函数没有实现体,含有纯虚函数的类,称为抽象基类

抽象基类不能实例化

java  中叫 interface接口,作用是给族类提供接口用的。

设计模式

高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象

高层业务逻辑==抽象层==低层业务逻辑

#include <iostream>

using namespace std;

class IReader
{
public:
    virtual void content();
};

class Story:public IReader
{
public:
    void content()
    {
        cout<<"story one"<<endl;
    }
};

class Newspaper:public IReader
{
public:
    void content()
    {
        cout<<"newspaper"<<endl;
    }
};

class Mother
{
public:
    void read_content(IReader * i)
    {
        i->content();
    }
};

int main()
{
    Mother mo;
    Story s;
    Newspaper ns;

    mo.read_content(&s);
    mo.read_content(&ns);

    return 0;
}

虚函数表

C++的多态是通过一张虚函数表(Virtual Table)来实现,简称为V-Table。

表中有虚函数的地址表,解决继承、覆写的问题,保证其真实反映实际的函数

这个表被分配在实例的内存中

静态代码

Base *b = new Derive();

b->f();

首先明确b的类型;然后通过指针虚函数表的指针vptr和偏移量,匹配虚函数的入口;根据入口地址调用虚函数

多态实现了动态绑定,但牺牲了一些空间和效率。

运行时类型信息(RTTI)

run time type identification

typeid dynamic_cast  只用于含有虚函数的父子类转化

Manager *t = dynamic_cast<Manager*>(emp[i]);

int main()
{
    B b;
    A * pa = &b;

    B * pb = dynamic_cast<B*>(pa);
    cout<<pb<<endl;  // 输出地址

    C * pc = dynamic_cast<C*>(pa);
    cout<<pc<<endl;  // 输出0

    return 0;
}

typeid

#include <iostream>
#include <typeinfo>

using namespace std;
typedef void (*PF)(int);

int main()
{
    //检查类型信息
    cout<<typeid(int).name()<<endl;  // i
    cout<<typeid(char).name()<<endl;  // c
    cout<<typeid(double).name()<<endl;  // d
    cout<<typeid(float).name()<<endl;  // f
    cout<<typeid(long).name()<<endl;  // l

    cout<<typeid(PF).name()<<endl;  //PFviE

    return 0;
}

B、C 均继承A
D是单独的类

int main()
{
    B b;
    A * pa = &b;
    
    B * pb = static_cast<B*>(pa);  // 成功
    cout<<pb<<endl;

    C * pc = static_cast<C*>(pa);  // 成功  不安全
    cout<<pc<<endl;

    D * pd = static_cast<D*>(pa);  // 不成功
    cout<<pd<<endl;

    

    B * pb = reinterpret_cast<B*>(pa);  //  成功 不安全
    cout<<pb<<endl;

    C * pc = reinterpret_cast<C*>(pa);  //  成功 不安全
    cout<<pc<<endl;

    D * pd = reinterpret_cast<D*>(pa);  //  成功 不安全
    cout<<pd<<endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/jiangyangll/article/details/132344004