6.11.  Review Questions

[ fromfile: inheritance-questions.xml id: inheritance-questions ]

  1. What is the difference between a function and a method?

      A method is a virtual function. A method call is resolved at runtime, a function call can be determined at compile-time.

  2. What does it mean for a base class function to be hidden? What can cause this to happen?

  3. Which member functions cannot be inherited from the base class? Explain why.

      The constructors, destructors, copy and assignment operators are all not inherited. They get generated for classes depending on certain rules, and the generated versions call base class versions.

  4. Given the definitions in Example 6.48, answer the questions in Example 6.49.

    Example 6.48. src/quizzes/virtual-quiz.cpp

    class Shape {
    public:
        virtual void draw(Position p);
        virtual void draw(PaintEngine* pe, Position p);
    };
    
    class Square : public Shape {
    public:
        void draw(Position p);
    private:
        void draw(int x, int y);
    };
    
    int main() {
        Position p(4,3);
        Position q(5,6);
        PaintEngine *pe = .....;
        Square sq;
    
        sq.draw(p);         1
        sq.draw(pe, p);     2
        sq.draw(3,3);       3
    
        Shape* sp = &sq;
        sp->draw(q);        4
        sp->draw(pe, q);    5
        sp->draw(3,2);      6
    
    }
    

    1

    ____________

    2

    ____________

    3

    ____________

    4

    ____________

    5

    ____________

    6

    ____________

    <include src="src/quizzes/virtual-quiz.cpp" link="false" mode="cpp" id="virtualquizcpp"/>


    Example 6.49. src/quizzes/virtual-questions.txt

    1. Which method is called?
       a. Shape::draw()
       b. Square::draw()
       c. error - method is hidden
       d. error - method is inaccessible
       e. error - no such method
    
    2. Which method is called?
       a. Shape::draw()
       b. Square::draw()
       c. error - method is hidden
       d. error - method is inaccessible
       e. error - no such method
    
    3. Which method is called?
       a. Shape::draw()
       b. Square::draw()
       c. error - method is hidden
       d. error - method is inaccessible
       e. error - no such method
    
    4. Which method is called?
       a. Shape::draw()
       b. Square::draw()
       c. error - method is hidden
       d. error - method is inaccessible
       e. error - no such method
    
    5. Which method is called?
       a. Shape::draw()
       b. Square::draw()
       c. error - method is hidden
       d. error - method is inaccessible
       e. error - no such method
    
    6. Which method is called?
       a. Shape::draw()
       b. Square::draw()
       c. error - method is hidden
       d. error - method is inaccessible
       e. error - no such method
    
    

    <include src="src/quizzes/virtual-questions.txt" href="src/quizzes/virtual-questions.txt" mode="txt" id="virtualquiz-questions.txt"/>


  5. Consider another shape class and answer the questions that follow. There can be more than one correct answer.

    Example 6.50. src/quizzes/abstract-quiz.cpp

    /* Consider the following header file, assume the
    function definitions are in a .cpp file somewhere. */
    class Shape {
    public:
        explicit Shape(Point origin);
        virtual void draw(PaintDevice* pd) = 0;
        virtual void fill(PaintDevice* pd) = 0;
        virtual String name() const;
        Point origin() const;
    private:
        Point m_origin;
    };
    
    class Rectangle : public Shape {
    public:
        Rectangle(Point origin, int width, int height);
        void draw(PaintDevice* pd);
    private:
        int m_width, m_height;
    };
    
    class Square: public Rectangle {
    public:
        Square(Point origin, int width);
    };
    
    /* 1. Which methods are pure virtual in all classes?
        a. origin
        b. draw
        c. fill
        d. draw and fill
        e. draw, fill, and name. */
    /* 2. Which classes are abstract?
         a. Shape
         b. Rectangle
         c. Square
         d. Shape and Rectangle
         e. All of them. */
    /* 3. Which of the following constructor implementations are valid?
    
          Rectangle::Rectangle(Point origin, int width, int height)
    
       a. { m_width = width; m_height = height; }
       b. : m_origin(origin), m_width(width), m_height(height) {}
       c. : Shape(origin) {m_width = width; m_height = height; }
       d. { m_origin = origin; m_width = width; m_height = height; }
       e. : Shape(origin), m_width(width), m_height(height) {}
    */
    

    <include src="src/quizzes/abstract-quiz.cpp" link="false" mode="cpp"/>


  6. Read the code in Example 6.51 and answer the questions in Example 6.52.

    Example 6.51. src/quizzes/virtual-destructors-quiz.cpp

    #include <QDebug>
    
    class Base {
    public:
        Base() { ++sm_bases; }
        ~Base() { --sm_bases; }
        void a();
        virtual void b();
    protected:
        static int sm_bases;
    };
    
    class Derived : public Base {
    public:
        Derived() { ++sm_deriveds; }
        ~Derived() { --sm_deriveds; }
        void a();
        void b();
        static void showCounts() {
            qDebug() << sm_bases << sm_deriveds;
        }
    protected:
        static int sm_deriveds;
    };
    
    int Base::sm_bases(0);
    int Derived::sm_deriveds(0);
    void Base::a() { qDebug() << "Base::a()" ;}
    void Base::b() { qDebug() << "Base::b()" ;}
    void Derived::a() { qDebug() << "Derived::a()" ;}
    void Derived::b() { qDebug() << "Derived::b()" ;}
    
    void foo() {
        Derived d1;
        Base b1;
        Base* bp = new Derived();
        bp->a();
        bp->b();
        delete bp;
        Derived::showCounts();       1
    }
    int main() {
        Base b;
        Derived d;
        foo();
        Derived::showCounts();       2
    }
    

    1

    __________

    2

    __________

    <include src="src/quizzes/virtual-destructors-quiz.cpp" link="false" mode="cpp" id="virtutaldtorquizcpp"/>


    Example 6.52. src/quizzes/virtual-destructors-quiz.txt

    1. What is the output from the first call to showCounts()?
        a. 4 3
        b. 3 2
        c. 2 2
        d. 1 1
        e. 3 4
    
    2. What is the output of the second call to showCounts()?
        a. 1 2
        b. 1 1
        c. 0 0
        d. 2 2
        e. 2 1

    <include src="src/quizzes/virtual-destructors-quiz.txt" href="src/quizzes/virtual-destructors-quiz.txt" mode="txt" id="virtutaldtorquiztxt"/>


  7. In Extended Example: A Simple Library, it is likely that items will be added to the RefCategory enum in the class ReferenceBook as the collection evolves. What pitfalls should be avoided and what rules should be imposed that would enable such growth to occur without encountering those pitfalls?

      If new items end up with values of existing items (e.g., if they were inserted alphabetically into the enum), data in existing files could have their m_Category member incorrectly cast. This can be avoided by making sure that existing enumerators retain their values. A simple rule to avoid the problem would be: New enumerators must always be added at the end of the enum list.