CIS-255 Home http://www.c-jump.com/bcc/c255c/c255syllabus.htm

Initializer lists and const qualifiers


  1. the this keyword
  2. Returning *this
  3. References as members
  4. The initializer list
  5. Initializer list usage
  6. Initializer list order
  7. An initializer list bug
  8. Adding "read-only" with const
  9. const reference in function arguments
  10. const class members
  11. How to initialize const static members
  12. For outdated compilers...
  13. const member functions
  14. const member function example
  15. const member function rules
  16. mutable data members
  17. mutable data members explained
  18. const and pointers
  19. more const and pointers
  20. OOP Philosophy

the this keyword


  • Majority of member functions never use the this pointer, because its use within the function is implicit:


class Point {
    // member variables
    int m_x;
    int m_y;

public:
    // member function
    void adjust( int x, int y )
    {
        this->m_x += x; // Ok, but redundant
        this->m_y += y;
    }
};

Returning *this


  • Problem: how to allow left-to-right function call chain? For example,


    String s1;
    String s2;
    String s3;

    s1.append( s2 ).append( s3 );

  • Solution: use *this:

    String& String::append( String& other )
    {
        // ...
        return *this; // "return myself"
    }
  • String::append( ) returns a reference to the object it was called on, so calls now can be chained.

References as members


The initializer list

    // point.h
    class Point
    {
    private:
        Graph& m_g;
        int    m_x;
        int    m_y;
    public:
        Point( Graph& g, int x, int y );
    };
  • New syntax for constructors:

        // point.cpp
        Point::Point( Graph& g, int x, int y )
        :   m_g( g )
        {
            m_x = x;
            m_y = y;
        }
  • or,

       // point.cpp
        Point::Point( Graph& g, int x, int y )
        :   m_g( g ),
            m_x( x ),
            m_y( y )
        {
        }

Initializer list usage


*) If you do not explicitly initialize a class member in the initializer list, the compiler automatically initializes it using member's default constructor. For objects without default constructor this could produce difficult to understand error messages.

Initializer list order

  • Initializer list order is restricted by the order of data member declarations in your class!

  • Because constructor call order is *very* important, modern compilers will generate errors when initializer list does not follow the order of class data members!

// point.h
class Graph { /*...*/ };
class Point {
private:
    Graph& m_g;
    int    m_x;
    int    m_y;
public:
    Point( Graph& g, int x, int y );
};
// point.cpp
Point::Point( Graph& g, int x, int y )
:
    m_x( x ),
    m_y( y ),
    m_g( g )  // out of order
{
}
// main.cpp
void main()
{
    Graph gr;
    Point pt( gr, 10, 20 );
}
  • When compiled with GNU GCC compiler version 3.4.5:

        main.cpp: In constructor 'Point::Point(Graph&, int, int)':
        main.cpp:9: warning: 'Point::m_g' will be initialized after
        main.cpp:7: warning:   'int Point::m_x'
        main.cpp:20: warning:   when initialized here

An initializer list bug


    // point.h
    class Graph { /*...*/ };
    class Point {
    private:
        Graph& m_g;
        int    m_x;
        int    m_y;
    public:
        Point( Graph& g, int x, int y );
    };
    // point.cpp
    Point::Point( Graph& g, int x, int y )
    :   m_g( g ),
        m_x( x ),
        m_y( m_x ) // UH-OH... m_x could still be garbage,
    {}             // so m_y might get it, too!
    // main.cpp
    void main()
    {
        Graph gr;
        Point pt( gr, 10, 20 );
    }

Adding "read-only" with const


const reference in function arguments


const class members


How to initialize const static members



    // point.h
    class Point
    {
        static const double PI;
    };

    // point.cpp
    // Note that static keyword here is an error!
    const double Point::PI = 3.14159;

For outdated compilers...


const member functions


const member function example


  • Modifying public data members is clearly not possible, but what about calling functions of str?

  • The answer is: the author of the String class specifies which functions of const str can be invoked.

// String.h
class String {
public:
    int length() const;
    void append( char* s );
private:
    int m_length;
    int m_bufSize;
};

// String.cpp
int String::length() const
{
    return m_length;
}

void myfunc( String const& str ) {
    int len = s.length(); // Ok
    s.append( "blah" );   // Compiler error
}

const member function rules


mutable data members


  • Solution:

// String.h
class String {
public:
    void reserve( int size ) const;
private:
    mutable int m_buffer_size;
    mutable char* m_ptr_buffer;
};

// String.cpp
void String::reserve( int size ) const
{
    if( m_buffer_size < size ) {
        // reallocate buffer memory, then copy
        // current string there, then...
        m_buffer_size = size; // OK, because
                // m_buffer_size declared mutable
    }
}

void myfunc( String const& str ) {
    str.reserve( 1024 ); // Ok
}

mutable data members explained


const and pointers



void main()
{
    double d = 3.5;
    const double CD = 4.5;
    double* ptr;          // pointer to double
    double const* ptr2cd; // pointer to const double
    ptr = &d;             // OK
    ptr = &CD; // Error: address of const can't be assigned to non-const pointer
    ptr2cd = &d;          // OK
    ptr2cd = &CD;         // OK
}

more const and pointers



void main()
{
    double d = 3.5;
    const double CD = 4.5;
    // const ptr to double
    double *const cptr = &d;  // OK
    double *const cptr = &CD; // Error: not const dbl
    double *const cptr;       // Error: must initialize
    // const ptr to const double
    const double* const cptr2 = &d;  // OK
    const double* const cptr2 = &CD; // OK
    const double* const cptr2;       // Error: must initialize
}

OOP Philosophy