19.12. Exercises: Types and Expressions

  1. Imagine you are required to use a library of classes that have been poorly written and you have no way to improve them. (It could happen!) Example 19.25 includes one such badly written example class and a small program that uses it. The program logic shows some objects being created and passed to a function that receives them as const references (an implicit vow not to change them) and then prints an arithmetic result. Unfortunately, because the class was badly written, something goes wrong along the way.

    Example 19.25. src/const/cast/const.cc

    #include <iostream>
    using namespace std;
    
    class Snafu {
    public:
        Snafu(int x) : mData(x) {}
        void showSum(Snafu & other) const {
            cout << mData + other.mData << endl; 
        }
      
    private:
        int mData;
    };
    
    void foo(const Snafu & myObject1,
             const Snafu & myObject2) {
        // [ . . . ]  
        myObject1.showSum(myObject2);
    }
    
    int main() {
    
        Snafu myObject1(12345);
        Snafu myObject2(54321);
    
        foo(myObject1, myObject2);
    
    }
    
    

    <include src="src/const/cast/const.cc" href="src/const/cast/const.cc" mode="cpp" id="constcc"/>


    Answer these questions.

    1. What went wrong?

    2. What change to the class would fix it?

    Unfortunately, you can't change the class. Come up with at least two ways to fix the program without changing the class definition. What would be the best of these and why?

     

    What went wrong was that the class was not const-correct. showSum should receive a const Snafu& parameter, but it was passed a regular Snafu&. Even though showSum doesn't change the passed-in object, the compiler barfs.

    To fix the program, you can:

    1. make foo receive the second parameter as non-const, or

    2. Apply a const_cast to myObject2 as you pass it to showSum:

       myObject1.showSum(const_cast<Snafu&>(myObject2));
             [111]
             

  2. Example 19.26 is an incomplete attempt to create a class that counts, for each instantiation, the number of times an object's data are printed. Review the program and make it work properly.

    Example 19.26. src/const/cast/const2.cc

    #include <iostream>
    using namespace std;
    
    class Quux {
    public:
        Quux(int initializer) :
            mData(initializer), printcounter(0) {}
        void print() const;
        void showprintcounter() const {
          cout << printcounter << endl; 
        }
    
    private:
        int mData;
        int printcounter;
    };
    
    void Quux::print() const {
        cout << mData << endl; 
    }
    
    int main() {
        Quux a(45);
        a.print();
        a.print();
        a.print();
        a.showprintcounter();
        const Quux b(246);
        b.print();
        b.print();
        b.showprintcounter();
        return 0;
    }
    
    

    <include src="src/const/cast/const2.cc" href="src/const/cast/const2.cc" id="const2cc" mode="cpp"/>


     

    You don't want to remove the const from print(). Anyone using this class would expect to be able to print both const and non-const objects. You cast away const-ness like this:

    ++const_cast< Quux * >( this )->printcounter;

    We relegate this to a separate function to make it very clear what is going on.

[ fromfile: types.xml id: None ]



[111] note the reference - const_cast works only on indirect types