Lecture Notes for CS 509, Advanced Programming II

27 November 2001, Classes and Conversions


  1. conversions - treat a value of one type as another type; a.k.a casting

    1. conversions can be convenient and simplifying

    2. conversions can be source of nasty compile- and run-time errors

      1. the compiler chooses automatically - you had better agree

  2. the many conversions of c++

    1. old style casts - (type); avoid

    2. static casts - perform the usual c++ casts

      1. static_cast<target-type>(val)

      2. examples - between T* and void *, int and double, and so on

      3. can modify data - make larger or smaller or round

    3. const casts - remove const or volatile modifiers

      1. const_cast<target-type>(val)

      2. only works on constant variables, not on constants

      3. usually a good sign that your approach is bad

    4. reinterpret cast - brute force casting, pure reinterpretation

      1. reinterpret_cast<target-type>(val)

      2. arbitrary pointer recasting

      3. doesn't do static casting

    5. dynamic cast - convert down the inheritance hierarchy; also known as downcasting

      1. dynamic_cast<target-type>(val)

      2. works on pointers

      3. if the source pointer isn't the target type, returns 0

      4. indicates possibly questionable designs

      5. part of the run-time type information (rtti) system

  3. classes and conversions

    1. classes can define implicit or explicit conversions

    2. implicit conversions are known as conversion constructors

      1. converts from other types to the class type - a static cast

      2. have a single parameter (effectively) - T::T(S sval)

      3. the complier uses conversion constructors when needed

        bignum::bignum(const char *) { ... }
        bignum & bignum::bignum = (const bignum & bn) { ... }
        
        bn = "10.3";
        

        "10.3" gets converted to a bignum, which gets assigned

      4. this can get confusing fast

        bignum::bignum(const string &) { ... }
        bignum & bignum::bignum == (const bignum & bn) { ... }
        bn = "10.3";
        

        "10.3" gets converted to a string, which gets converted to a bignum, which gets assigned

      5. the compiler takes the shortest sequence of conversions it finds

      6. can turn typos into subtle programming errors

        1. the explicit keyword can prevent these problems

    3. explicit conversions convert from the class type to other types

      1. operator target-type () - no return type, no arguments

      2. defines a static cast

        bignum::bignum(const string &) { ... }
        bignum::operator string () { ... }
        
        bignum bn = static_cast(string("10.3"));
        cout << static_cast<string>(bn) << "\n";
        

      3. however, the compiler may implicitly use them too

  4. user-defined conversions - be careful

    1. try to avoid if possible

      1. they are seductive (because useful) and tricky (inadvertent definitions)

    2. they are near-term useful, but long-term trouble

      1. compilcate program understanding - e.g. overloading

      2. turn compile-time bad code into run-time bad code

      3. they are implicit, invisible, and compiler determined

    3. mark single-parameter constructors as explicit

    4. don't define conversion operators - use member functions

      string bignum::get_string(void) const { return ...; }
      
      cout << bn.get_string() << "\n";
      

    5. if you must define them, define an absolute minimal set


This page last modified on 27 November 2001.