zoukankan      html  css  js  c++  java
  • C++程序设计POJ》《WEEK6 多态与虚函数》

    问题: 虚函数都是同名 同参数表的吗? 

    虚函数和普通成员函数的区别

    虚函数可以多态,其他不行

    在构造函数和析构函数中调用 虚函数 不是多态

    派生类还没有初始化好

    MyCompare()

    qsort 怎么表示排序关系

    虚函数表地址!!

    虚函数

    在类的定义中,前面有 virtual 关键字的成员
    函数就是虚函数。
    class base{

    virtual   int get() };

    int base::get()
    { }

    virtual 关键字只用在类定义里的函数声明中
    写函数体时不用。
    多态的表现形式一


    派生类的指针可以赋给基类指针

    通过基类指针调用基类和派生类中的同名 虚函数

    1 )若该指针指向一个基类的对象,那么被调用
    基类的 虚函数

    2 )若该指针指向一个派生类的对象,那么被调
    用的是派生类的 虚函数
    这种机制就叫做“
    多态 ”。

    class CBase {
    public:
    virtual  void SomeVirtualFunction() { }
    };
    class CDerived:public CBase {
    public :
    virtual  void SomeVirtualFunction() { }
    };
    int main() {
    CDerived ODerived;
    CBase * p = & ODerived; 
    p-> SomeVirtualFunction(); // 调用哪个虚函数取决于 p 指向哪种类型的对象  调用CDerived类的虚函数
    return 0;
    }

    多态的表现形式二

    派生类的对象可以赋给基类引用

    通过基类引用调用基类和派生类中的同名 虚函数 时

    1 )若该引用引用的是一个基类的对象,那么被
    调用是基类的 虚函数

    2 )若该引用引用的是一个派生类的对象,那么
    被调用的是派生类的 虚函数 。
    这种机制也叫做“
    多态 ”。

    class CBase {
    public:
    virtual
    void SomeVirtualFunction() { }
    };
    class CDerived:public CBase {
    public :
    virtual
    void SomeVirtualFunction() { }
    };
    int main() {
    CDerived ODerived;
    CBase & r = ODerived;
    r.SomeVirtualFunction(); //调用哪个虚函数取决于 r 引用哪种类型的对象
    return 0;
    }

    多态的作用

    在面向对象的程序设计中使用多态,能够增强
    程序的 可扩充性 ,即程序需要修改或增加功能
    的时候,需要改动和增加的代码较少。

    /*
    几何形体处理程序
    Sample Input:
    3
    R 3 5
    C 9
    T 3 4 5
    Sample Output
    Triangle:6
    Rectangle:15
    Circle:254.34
    39
    */
    #include<iostream>
    #include<stdlib.h>
    #include<math.h>
    
    using namespace std;
    class CShape
    {
    public:
        virtual double Area() = 0; // 纯虚函数
        virtual void PrintInfo() = 0;
    };
    
    class CRectangle :public CShape
    {
    public:
        int w, h;
        virtual double Area();
        virtual void PrintInfo();
    };
    class CCircle :public CShape
    {
    public:
        int r;
        virtual double Area();
        virtual void PrintInfo();
    
    };
    class CTriangle :public CShape
    {
    public:
        int a, b, c;
        virtual double Area();
        virtual void PrintInfo();
    };
    double CRectangle::Area()
    {
        return w*h;
    }
    void CRectangle::PrintInfo()
    {
        cout << "rectanlgle:" << Area() << endl;
    }
    
    double CCircle::Area()
    {
        return 3.14*r*r;
    }
    void CCircle::PrintInfo()
    {
        cout << "circle:" << Area() << endl;
    }
    double CTriangle::Area()
    {
        double p = (a + b + c) / 2.0;
        return sqrt(p*(p - a)*(p - b)*(p - c));
    }
    void CTriangle::PrintInfo()
    {
        cout << "triangle:" << Area() << endl;
    }
    
    CShape * pShapes[100]; // 基类 指针数组
    int MyCompare(const void *s1, const void *s2);
    
    int MyCompare(const void* s1, const void *s2)
    {
        double a1, a2;
        CShape** p1; // s1,s2 是 void * ,不可写 ““* s1 ”来取得 s1 指向的内容
        CShape** p2;
        p1 = (CShape**)s1;//s1,s2 指向 pShapes 数组中的元素,数组元素的类型是 CShape *
        p2 = (CShape**)s2;// 故 p1,p2 都是指向指针的指针,类型为 CShape **
        a1 = (*p1)->Area();// * p1 的类型是 Cshape * , 是基类指针,故此句为多态
        a2 = (*p2)->Area();
        if (a1 < a2)
            return -1;
        else if (a2 < a1)
            return 1;
        else
            return 0;
    }
    int main()
    {
        int i, n;
        CRectangle *pr;
        CCircle *pc;
        CTriangle *pt;
        cin >> n;
        for (i = 0; i < n; i++)
        {
            char c;
            cin >> c;
            switch (c)
            {
            case 'R':
                pr = new CRectangle();
                cin >> pr->w >> pr->h;
                pShapes[i] = pr; // 派生类指针 赋给 基类
                break;
            case 'C':
                pc = new CCircle;
                cin >> pc->r;
                pShapes[i] = pc;
                break;
            case 'T':
                pt = new CTriangle();
                cin >> pt->a >> pt->b >> pt->c;
                pShapes[i] = pt;
                break;
    
            }
        }
    
        qsort(pShapes, n, sizeof(CShape*), MyCompare);
        for (i = 0; i < n; i++)
            pShapes[i]->PrintInfo();
        while (1);
        return 0;
    }

    用基类指针数组存放指向各种派生类对象的指
    针,然后遍历该数组,就能对各个派生类对象
    做各种操作,是很常用的做法

    构造函数和析构函数中调用虚函数

    在构造函数和析构函数中调用虚函数,不是多态。编
    译时即可确定,调用的函数是 自己的类或基类 中定义
    的函数,不会等到运行时才决定调用自己的还是派生
    类的函数。

    派生类中和基类中虚函数同名同参数表的函数,不加
    virtual 也自动成为虚函数

    #include <iostream> 
    using namespace std;
    
    class myclass
    {
    public:
        virtual void hello() { cout << "hello from myclass" << endl; };
        virtual void bye() { cout << "bye from myclass" << endl; }
    };
    class son :public myclass
    {
    public:
        void hello() { cout << "hello from son" << endl; }
        son() { hello(); }
        ~son() { bye(); }
    };
    
    class grandson :public son
    {
    public:
        void hello()
        {
            cout << "hello from grandson" << endl;
        }
        void bye() 
        {
            cout << "bye from grandson" << endl;
        }
        grandson()
        { 
            cout << "constructing grandson" << endl;
        }
        ~grandson() { cout << "destructing grandson" << endl; }
    };
    
    int main() {
        grandson gson;
        son *pson; // 不会调用构造函数?因为指针不需要分配内存空间?
        pson = &gson;
        pson->hello();  //多态
        return 0;
    }
    //派生类中和基类中虚函数同名同参数表的函数,不加virtual 也自动成为虚函数
    /*
    结果:
    hello from son
    constructing grandson
    hello from grandson
    destructing grandson
    bye from myclass
    */

    虚函数的访问权限

    class Base {
    private:
    virtual void fun2() { cout << "Base::fun2()" << endl; }
    };
    class Derived:public Base {
    public:
    virtual void fun2() { cout << "Derived:fun2()" << endl; }
    };
    Derived d;
    Base * pBase = & d;
    pBase-> fun2(); // 编译出错

    编译出错是因为 fun2() 是 Base 的私有成员。即使运行到此时实际上调用的应该是
    Derived 的公有成员 fun2() 也不行,因为语法检查是不考虑运行结果的。

    如果 将 Base 中的 private 换成 public, 即使 Derived 中的 fun2() 是 private 的,编译依然能通
    过,也能正确调用 Derived::fun2() 。

    #include<iostream>
    using namespace std;
    class Base
    {
    public:
        virtual void fun2()
        {
            cout << "base::fun2()" << endl;
        }
    };
    class Derived :public Base
    {
    private:
        virtual void fun2()
        {
            cout << "Derived:fun2()" << endl;
        }
    };
    
    int main()
    {
        Derived d;
        Base * pBase = &d;
        pBase->fun2(); // 神奇了,private也能访问!!!
        while (1);
        return 0;
    
    }
  • 相关阅读:
    你的灯亮着么阅读笔记2
    你的灯亮着么阅读笔记1
    梦断代码阅读笔记3
    梦断代码阅读笔记2
    梦断代码阅读笔记1
    百度搜索分析
    有多少1
    寻找“水王”问题
    站立会议
    买书的最低价格问题
  • 原文地址:https://www.cnblogs.com/focus-z/p/11074587.html
Copyright © 2011-2022 走看看