zoukankan      html  css  js  c++  java
  • 《C++ primerplus》第13章练习题

     

    1.对CD类的派生练习。基类CD类存储作者和作品号等信息,派生类Classic额外增加一格“主要作品”的信息。主函数使用拷贝构造函数、按引用传递参数的函数和指针来测试基类和派生类的功能。

    注意继承类和基类的权限关系、初始化成员列表的使用。

    class.h

    #ifndef _CLASS_H_
    #define _CLASS_H_
    
    #include <iostream>
    using std::cin;
    using std::cout;
    
    class CD
    {
    private:
        char performers[20] = {};    //初始化为空,不然输出一堆烫
        char label[20] = {};
        int selections;
        double playtime;
    
    public:
        CD(const char *s1, const char*s2, int n, double x);    //自定义构造函数
        CD(const CD & d);    //拷贝构造函数
        CD();    //默认构造函数
        virtual ~CD();
        virtual void Report()const;
        virtual CD & operator = (const CD & d);
    
    };
    
    class Classic :public CD
    {
    private:
        char collection[50] = {};
    
    public:
        Classic(const char *c, const char *s1, const char*s2, int n, double x);
        Classic();
        ~Classic();
        void Report()const;
        Classic & operator = (const Classic & d);
    };
    
    #endif

    DefineClass.cpp

    #include "class.h"
    
    CD::CD(const char *s1, const char*s2, int n, double x)
    {
        for (int i = 0; s1[i] != ''; i++)
        {
            performers[i] = s1[i];
        }
        for (int i = 0; s2[i] != ''; i++)
        {
            label[i] = s2[i];
        }
        selections = n;
        playtime = x;
    }
    
    CD::CD(const CD & d)
    {
        for (int i = 0; d.performers[i] != ''; i++)
        {
            performers[i] = d.performers[i];
        }
        for (int i = 0; d.label[i] != ''; i++)
        {
            label[i] = d.label[i];
        }
        selections = d.selections;
        playtime = d.playtime;
    }
    
    CD::CD()
    {
    
    }
    
    CD::~CD()
    {
    
    }
    
    void CD::Report()const
    {
        cout << "Performers: ";
        for (int i = 0; performers[i] != ''; i++)
        {
            cout << performers[i];
        }
        cout << "
    ";
        cout << "Label: ";
        for (int i = 0; label[i] != ''; i++)
        {
            cout << label[i];
        }
        cout << "
    ";
        cout << "Selections: " << selections << "
    ";
        cout << "Playtime: " << playtime << "
    ";
    }
    
    CD & CD::operator=(const CD & d)
    {
        for (int i = 0; d.performers[i] != ''; i++)
        {
            performers[i] = d.performers[i];
        }
        for (int i = 0; d.label[i] != ''; i++)
        {
            label[i] = d.label[i];
        }
        selections = d.selections;
        playtime = d.playtime;
    
        return *this;
    }
    
    //derived class
    
    Classic::Classic(const char *c, const char *s1, const char*s2, int n, double x):CD(s1,s2,n,x)
    {
        for (int i = 0; c[i] != ''; i++)
        {
            collection[i] = c[i];
        }
    }
    
    Classic::Classic()
    {
    
    }
    
    Classic::~Classic()
    {
    
    }
    
    void Classic::Report()const 
    {
        CD::Report();
        cout << "Collection: ";
        for (int i = 0; collection[i] != ''; i++)
        {
            cout << collection[i];
        }
        cout << "
    
    ";
    }
    
    Classic & Classic::operator = (const Classic & d)
    {
        CD::operator=(d);
        for (int i = 0; d.collection[i] != ''; i++)
        {
            collection[i] = d.collection[i];
        }
        return *this;
    }

    main.cpp

    #include "class.h"
    
    void Bravo(const CD & disk);
    
    int main()
    {
        CD c1("Beatles", "Capitol", 14, 35.5);
        Classic c2 = Classic("Piano Sonata in B flat, Fantasia in C", "Alfred Brendel", "Philips", 2, 57.17);
    
        CD *pcd = &c1;
    
        cout << "Using Object directly:
    ";
        c1.Report();
        c2.Report();
    
        cout << "Using type cd * pointer to objects:
    ";
        pcd->Report();
        pcd = &c2;
        pcd->Report();
    
        cout << "Calling a function with a cd reference argument:
    ";
        Bravo(c1);
        Bravo(c2);
    
        cout << "Testing assignment:
    ";
        Classic copy;
        copy = c2;
        copy.Report();
    
        //pause
        cin.get();
        return 0;
    
    }
    
    void Bravo(const CD & disk)
    {
        disk.Report();
    }

    2.以上题为基础。存储的字符数组用使用动态分配内存。

    我初始化对象的时候把两个字符成员都设为了空指针,做题的过程中,了解到了空指针不能被赋值。其它需要注意的地方见注释。

    ClassCD.h

    #ifndef _CLASSCD_
    #define _CLASSCD_
    
    #include <iostream>
    
    using std::cout;
    using std::cin;
    
    //Base Class Declare
    class CD
    {
    private:
        char *performers = nullptr;
        char *label = nullptr;
        int selections;
        double playtime;
    
    public:
        CD(const char *s1, const char*s2, int n, double x);    //自定义构造函数
        CD(const CD & d);    //拷贝构造函数
        CD();    //默认构造函数
        virtual ~CD();
        virtual void Report()const;
        virtual CD & operator = (const CD & d);
    };
    
    //Base Class Define
    CD::CD(const char *s1, const char*s2, int n, double x)
    {
        //根据s1和s2的长度分配内存
        //strlen()计算的长度不包含终止符''
        //为了不影响report()的执行,分配的内存长度+1,使其包含''
        performers = new char[strlen(s1)+1];
        for (int i = 0; i < (strlen(s1)+1); i++)
        {
            performers[i] = s1[i];
        }
    
        label = new char[strlen(s2)+1];
        for (int i = 0; i < (strlen(s2)+1); i++)
        {
            label[i] = s2[i];
        }
    
        selections = n;
        playtime = x;
    }
    
    CD::CD()
    {
        selections = 0;
        playtime = 0;
    }
    
    CD::CD(const CD & d)
    {
        int count;
    
        //对象分配内存的成员不是空指针才会赋值,防止内存访问混乱
        if (d.performers != nullptr)
        {
            //获取等号右边的类里面分配的长度
            for (count = 0; d.performers[count] != ''; count++)
            {
                ;
            }
    
            //根据它的长度来分配自身的长度,加上''一位
            performers = new char[count + 1];
    
            //给自身成员变量赋值,取到终止符后停止
            for (int i = 0; d.performers[i] != ''; i++)
            {
                performers[i] = d.performers[i];
                if (d.performers[i + 1] == '')
                {
                    performers[i + 1] = '';
                    break;
                }
            }
        }
    
        //以下同理
        if (d.label != nullptr)
        {
            for (count = 0; d.label[count] != ''; count++)
            {
                ;
            }
    
            label = new char[count + 1];
    
            for (int i = 0; d.label[i] != ''; i++)
            {
                label[i] = d.label[i];
                if (d.label[i + 1] == '')
                {
                    label[i + 1] = '';
                    break;
                }
            }
        }
        
        selections = d.selections;
        playtime = d.playtime;
    }
    
    CD::~CD()
    {
        //是空指针,说明从未分配过内存,不需要释放
        //不是空指针,说明分配了内存,需要释放
        if (performers != nullptr)
        {
            delete[] performers;
        }
        if (label != nullptr)
        {
            delete[] label;
        }
    }
    
    void CD::Report()const
    {
        //对象分配内存的成员不是空指针才会打印,防止内存访问混乱
        cout << "Performers: ";
        if (performers != nullptr)
        {
            for (int i = 0; performers[i] != ''; i++)
            {
                cout << performers[i];
            }
        }
        cout << "
    ";
    
        cout << "Label: ";
        if (label != nullptr)
        {
            for (int i = 0; label[i] != ''; i++)
            {
                cout << label[i];
            }
        }
        cout << "
    ";
    
        cout << "Selections: " << selections << "
    ";
        cout << "Playtime: " << playtime << "
    ";
    }
    
    CD & CD::operator=(const CD & d)
    {
        int count;
    
        //对象分配内存的成员不是空指针才会赋值,防止内存访问混乱
        if (d.performers != nullptr)
        {
            //获取等号右边的类里面分配的长度
            for (count = 0; d.performers[count] != ''; count++)
            {
                ;
            }
    
            //根据它的长度来分配自身的长度,加上''一位
            performers = new char[count + 1];
    
            //给自身成员变量赋值,取到终止符后停止
            for (int i = 0; d.performers[i] != ''; i++)
            {
                performers[i] = d.performers[i];
                if (d.performers[i + 1] == '')
                {
                    performers[i + 1] = '';
                    break;
                }
            }
        }
    
        //以下同理
        if (d.label != nullptr)
        {
            for (count = 0; d.label[count] != ''; count++)
            {
                ;
            }
    
            label = new char[count + 1];
    
            for (int i = 0; d.label[i] != ''; i++)
            {
                label[i] = d.label[i];
                if (d.label[i + 1] == '')
                {
                    label[i + 1] = '';
                    break;
                }
            }
        }
        
        selections = d.selections;
        playtime = d.playtime;
    
        return *this;
    }
    
    //Derived Class Declare
    class Classic :public CD
    {
    private:
        char *collection = nullptr;
    
    public:
        Classic(const char *c, const char *s1, const char*s2, int n, double x);
        Classic();
        ~Classic();
        void Report()const;
        Classic & operator = (const Classic & d);
    };
    
    //Derived Class Define
    Classic::Classic(const char *c, const char *s1, const char*s2, int n, double x) :CD(s1, s2, n, x)
    {
        collection = new char[strlen(c) + 1];
        for (int i = 0; i < (strlen(c) + 1); i++)
        {
            collection[i] = c[i];
        }
    }
    
    Classic::Classic()
    {
        
    }
    
    Classic::~Classic()
    {
        if (collection != nullptr)
        {
            delete[] collection;
        }
    }
    
    void Classic::Report()const
    {
        CD::Report();
        cout << "Collection: ";
        if (collection != nullptr)
        {
            for (int i = 0; collection[i] != ''; i++)
            {
                cout << collection[i];
            }
        }
        cout << "
    
    ";
    }
    
    Classic & Classic::operator = (const Classic & d)
    {
        CD::operator=(d);
        int count;
    
        if (d.collection != nullptr)
        {
            for (count = 0; d.collection[count] != ''; count++)
            {
                ;
            }
    
            collection = new char[count + 1];
    
            for (int i = 0; d.collection[i] != ''; i++)
            {
                collection[i] = d.collection[i];
                if (d.collection[i + 1] == '')
                {
                    collection[i + 1] = '';
                    break;
                }
            }
        }
    
        return *this;
    }
    
    
    #endif

    main.cpp

    #include "ClassCD.h"
    
    void Bravo(const CD & disk);
    
    int main()
    {
        CD c1("Beatles", "Capitol", 14, 35.5);
        Classic c2 = Classic("Piano Sonata in B flat, Fantasia in C", "Alfred Brendel", "Philips", 2, 57.17);
    
        CD *pcd = &c1;
    
        cout << "Using Object directly:
    ";
        c1.Report();
        c2.Report();
    
        cout << "Using type cd * pointer to objects:
    ";
        pcd->Report();
        pcd = &c2;
        pcd->Report();
    
        cout << "Calling a function with a cd reference argument:
    ";
        Bravo(c1);
        Bravo(c2);
    
        cout << "Testing assignment:
    ";
        Classic copy;
        copy = c2;
        copy.Report();
    
        //pause
        cin.get();
        return 0;
    
    }
    
    void Bravo(const CD & disk)
    {
        disk.Report();
    }

    3.不想使用原题所以没用,目的是练习抽象基类的继承。

    所谓抽象基类,就是把定义的基类之中的虚成员函数声明为纯虚的(virtual修饰的函数后面加个 = 0),那么这个基类就只能用于继承,而不能实例化。一旦在代码里试图去实例化,编译之前就会提示“不允许使用抽象类型XXX的对象”。

    抽象基类是抽象出一系列对象的共性的做法,方便派生出许多相似的对象。 需要注意,基类定义的纯虚函数不给出定义,而由所有派生类给出自己的定义。

    下面是自己简单的练习。定义一个MovingObject的抽象基类,nowwhere()显示当前目标的位置,set_speed()设定目标的速度。从MovingObject派生出Car和Plane对象,各自的构造函数、析构函数、nowwhere()和set_speed()方法都不同。Car类会在坐标轴上按上下左右四个方向移动,Plane类指定一个目标地点,用动态数组的方式存储和打印该地点。

    class.h

    #ifndef _CLASS_H_
    #define _CLASS_H_
    
    #include <iostream>
    #include <string>
    
    using std::cout;
    using std::cin;
    using std::string;
    
    /* Abstract Base Class */
    class MovingObject
    {
    protected:
        double x;
        double y;
        double v;
        string name;
    
    public:
        MovingObject();
        virtual ~MovingObject();
        virtual void nowwhere() = 0;    //pure virtual function
        virtual void set_speed(unsigned int vv) = 0;    //pure virtual function
    };
    
    MovingObject::MovingObject()
    {
    }
    
    MovingObject::~MovingObject()
    {
    }
    
    /* Derived Class A */
    class Car :public MovingObject
    {
    public:
        enum car_direction
        {
            UP = 0,
            DOWN,
            LEFT,
            RIGHT,
            RESET
        }drive_to;
    
    private:
    
    public:
        Car();
        Car(const double xx, const double yy);
        ~Car();
        void move(car_direction drive_to,double t);
        void nowwhere();
        void set_speed(unsigned int vv);
    };
    
    Car::Car()
    {
        name = "car";
        x = 0;
        y = 0;
        v = 30;
        cout << "A new car constructed.
    ";
    }
    
    Car::Car(const double xx, const double yy)
    {
        name = "car";
        x = xx;
        y = yy;
        v = 30;
        cout << "A new car constructed.
    ";
    }
    
    Car::~Car()
    {
        cout << "Car decontructed
    ";
    }
    
    void Car::move(car_direction drive_to = RESET,double t = 0)
    {
        switch (drive_to)
        {
            case(UP):
            {
                cout << "The car's moving up, " << "with " << v << " m/s in " << t << " s.
    ";
                y = y + v * t;
                break;
            }
            case(DOWN):
            {
                cout << "The car's moving down, " << "with " << v << " m/s in " << t << " s.
    ";
                y = y - v * t;
                break;
            }
            case(LEFT):
            {
                cout << "The car's moving left, " << "with " << v << " m/s in " << t << " s.
    ";
                x = x - v * t;
                break;
            }
            case(RIGHT):
            {
                cout << "The car's moving right, " << "with " << v << " m/s in " << t << " s.
    ";
                x = x + v * t;
                break;
            }
            case(RESET):
            {
                cout << "The car's at (0,0).
    ";
                x = 0;
                y = 0;
                v = 1;
                break;
            }
            default:
            {
                break;
            }
        }
    }
    
    void Car::nowwhere()
    {
        cout << name << " is at (" << x << "," << y << ").
    ";
    }
    
    void Car::set_speed(unsigned int vv)
    {
        v = vv;
    }
    
    /* Derived Class B */
    class Plane:public MovingObject
    {
    private:
        char *flywhere;
    
    public:
        Plane();
        ~Plane();
        void nowwhere();
        void set_speed(unsigned int vv);
    
    };
    
    Plane::Plane()
    {
        flywhere = new char[20];
        char wishplace[20] = {};
        v = 180;
        cout << "A plane just arrived.
    ";
        cout << "Assign one destination you wish: ";
        cin >> wishplace;
        for (int i = 0; i < (strlen(wishplace)+1); i++)
        {
            flywhere[i] = wishplace[i];
        }
    }
    
    Plane::~Plane()
    {
        cout << "Plane deconstructed.
    ";
        delete[] flywhere;
    }
    
    void Plane::nowwhere()
    {
        cout << "The plane's flying at " << v << " m/s.
    ";
        cout << "Finally it arrived at ";
        for (int i = 0; flywhere[i] != ''; i++)
        {
            cout << flywhere[i];
        }
        cout << ".
    ";
    }
    
    void Plane::set_speed(unsigned int vv)
    {
        cout << "Changing speed to (150~250): ";
        if ((vv >= 150) && (vv <= 250))
        {
            v = vv;
        }
        else
        {
            cout << "Invalid speed! (Current: " << v << " m/s.)";
        }
    }
    
    
    #endif

    main.cpp

    #include "Class.h"
    
    int main()
    {
        Car car1;
        car1.move(Car::UP,10);
        car1.nowwhere();
    
        Plane plane1;
        plane1.set_speed(180);
        plane1.nowwhere();
    
        //pause
        cin.get();
        cin.get();
    
        return 0;
    
    }

    输出结果:

    4.派生练习。定义存储酒相关信息的类和派生类。

    对原题问题的回答:

    (a)见代码。

    (b)Port有所有默认参数的构造函数和默认构造函数冲突了。

    (c)运算符=重载的函数应用的对象算不同的类型,运算符<<重载的函数是友元函数,友元函数不归属于类,也不能被继承,所以不需要声明为虚。

    (d)见代码。

    Class.h

    #ifndef _CLASS_H_
    #define _CLASS_H_
    
    #include <iostream>
    using std::ostream;
    using std::cout;
    using std::cin;
    
    //Base Class
    class Port
    {
    private:
        char * brand;
        char style[20];        //tawny,ruby,vintage...
        int bottles;
    
    public:
        Port(const char *br, const char *st, int b);    //重新定义,去掉默认参数,防止与默认构造函数重复
        Port();    //创建的默认构造函数
        Port(const Port & p);
        virtual ~Port() { delete[]brand; }
        Port & operator = (const Port & p);
        Port & operator += (int b);        //add bottles
        Port & operator -= (int b);
        int BottleCount()const { return bottles; }
        virtual void show()const;
        friend ostream & operator << (ostream & os, const Port & p);
    };
    
    Port::Port(const char *br, const char *st, int b = 0)
    {
        brand = new char[strlen(br) + 1];
        for (int i = 0; i < (strlen(br) + 1); i++)
        {
            brand[i] = br[i];
        }
        for (int i = 0; i < (strlen(st) + 1); i++)
        {
            style[i] = st[i];
        }
        bottles = b;
    
    }
    
    Port::Port()
    {
        brand = new char[20];
        brand[0] = '';
        style[0] = '';
        bottles = 0;
            
    }
    
    Port::Port(const Port & p)
    {
        for (int i = 0; i<strlen(p.brand)+1; i++)
        {
            brand[i] = p.brand[i];
        }
        for (int i = 0; p.style[i]!=''; i++)
        {
            style[i] = p.style[i];
        }
        bottles = p.bottles;
    
    }
    
    Port & Port::operator = (const Port & p)
    {
        for (int i = 0; i<strlen(p.brand)+1; i++)
        {
            brand[i] = p.brand[i];
        }
        for (int i = 0; i < strlen(p.style) + 1; i++)
        {
            style[i] = p.style[i];
        }
        bottles = p.bottles;
    
        return *this;
    }
    
    Port & Port::operator += (int b)
    {
        bottles += b;
        return *this;
    }
    
    Port & Port::operator -= (int b)
    {
        bottles -= b;
        return *this;
    }
    
    void Port::show()const
    {
        cout << "Brand:";
        for (int i = 0; brand[i] != ''; i++)
        {
            cout << brand[i];
        }
        cout << "
    ";
        cout << "Kind:";
        for (int i = 0; style[i] != ''; i++)
        {
            cout << style[i];
        }
        cout << "
    ";
        cout << "Bottles:" << bottles << "
    ";
    }
    
    ostream & operator << (ostream & os, const Port & p)
    {
        os << "Brand:";
        for (int i = 0; p.brand[i] != ''; i++)
        {
            cout << p.brand[i];
        }
        os << "
    ";
        os << "Kind:";
        for (int i = 0; p.style[i] != ''; i++)
        {
            os << p.style[i];
        }
        os << "
    ";
        os << "Bottles:" << p.bottles << "
    ";
    
        return os;
    
    }
    
    //Derived Class
    class VintagePort :public Port
    {
    private:
        char *nickname;
        int year;
    
    public:
        VintagePort();
        VintagePort(const char * br, int b, const char *nn, int y);
        VintagePort(VintagePort & vp);
        ~VintagePort() { delete[]nickname; }
        VintagePort & operator = (const VintagePort & vp);
        void show() const;
        friend ostream & operator << (ostream & os, const VintagePort & vp);
    };
    
    VintagePort::VintagePort()
    {
        nickname = new char[20];
        nickname[0] = '';
        year = 0;
    }
    
    VintagePort::VintagePort(const char * br, int b, const char *nn, int y):Port(br,"none",b)
    {
        nickname = new char[strlen(nn) + 1];
        for (int i = 0; i < strlen(nn) + 1; i++)
        {
            nickname[i] = nn[i];
        }
        year = y;
    }
    
    VintagePort::VintagePort(VintagePort & vp)
    {
        for (int i = 0; i < strlen(vp.nickname) + 1; i++)
        {
            nickname[i] = vp.nickname[i];
        }
        year = vp.year;
    }
    
    void VintagePort::show()const
    {
        Port::show();
        cout << "Nickname:";
        for (int i = 0; nickname[i] != ''; i++)
        {
            cout << nickname[i];
        }
        cout << "
    ";
        cout << "Year:" << year;
        cout << "
    ";
    }
    
    VintagePort & VintagePort::operator = (const VintagePort & vp)
    {
        Port::operator=(vp);
    
        for (int i = 0; i < strlen(vp.nickname) + 1; i++)
        {
            nickname[i] = vp.nickname[i];
        }
        year = vp.year;
    
        return *this;
    }
    
    ostream & operator << (ostream & os, const VintagePort & vp)
    {
        cout << "Nickname:";
        for (int i = 0; vp.nickname[i] != ''; i++)
        {
            os << vp.nickname[i];
        }
        os << "
    ";
        os << "Year:" << vp.year;
        os << "
    ";
    
        return os;
    
    }
    
    #endif

    main.cpp

    #include "Class.h"
    
    int main()
    {
        cout << "-- p1 using default constructor -- 
    ";
        Port p1;
        p1.show();
    
        cout << "-- p2 using custom constructor -- 
    ";
        Port p2("Gallo", "vintage", 20);
        p2.show();
    
        cout << "-- p2 add 20 bottles -- 
    ";
        p2 += 20;
        p2.show();
    
        cout << "-- copy p2 -> p1 -- 
    ";
        p1 = p2;
        p1.show();
    
        cout << "-- cout << p1 -- 
    ";
        cout << p1;
    
        cout << "-- vp1 using default constructor -- 
    ";
        VintagePort vp1;
        vp1.show();
    
        cout << "-- vp2 using custom constructor -- 
    ";
        VintagePort vp2("Ruby", 10, "pussy", 1998);
        vp2.show();
    
        cout << "-- copy vp2 -> vp1 -- 
    ";
        p1 = p2;
        vp1 = vp2;
        vp1.show();
    
        cout << "-- copy p2 -> p1 -- 
    ";
        p1 = p2;
        cout << vp2;
    
        cout << "-- cout << vp1 -- 
    ";
        cout << vp1;
    
        //pause
        cin.get();
    
        return 0;
    
    }
  • 相关阅读:
    uva 12034 Race
    计算机基础之计算机硬件软件数据结构
    Project Perfect让Swift在server端跑起来-Perfect in Visual Studio Code (四)
    关于自己定义转场动画,我都告诉你。
    Shell编程入门
    CODEVS 1029 遍历问题
    【VBA研究】工作表自己主动筛选模式检測
    卸载MySQL 5.0
    操作系统(二)进程控制
    前端面试题
  • 原文地址:https://www.cnblogs.com/banmei-brandy/p/12005387.html
Copyright © 2011-2022 走看看