Sunday, May 1, 2011

C++ polymorphic shock of passing derived object arrays into a base object pointer function parameter

Code example:

#include <cstdio>

class Mammal
{
public:
    virtual bool IsFurry() = 0;
};

class Dog : public Mammal
{
    bool isFurryBreed;
public:
    Dog() { isFurryBreed = false; }

    virtual bool IsFurry()
    {
        return isFurryBreed;
    }
};

//the line below didn't compile
//int FindFurryMammal(Mammal pMammals[], int arraySize)
int FindFurryMammal( Mammal *pMammals, int arraySize)
{
    for( int i = 0; i < arraySize; i++ )
    {
        if( pMammals[i].IsFurry() )
        {
            return i;
        }
    }
    return -1;
}

int main(int argc, char * argv[])
{
    Dog dogs[10];
    int found;

    found = FindFurryMammal(dogs, 10);

    printf("Furry mammal found at index %d\n", found);
    
    return 0;
}

The code above suffers from polymorphic shock. Indexing through pMammals would be ok if polymorphism downcasted all the indices of Dog into the Mammal base class. However, polymorphism can only cast one index at a time even if passed as a parameter to a function.
So two issues ensue where only the first index of Dog is casted to Mammal, and therefore, any indexing beyond index 0 of pMammals will result in the indexing of incorrect memory location. This results in an exception error thrown at run-time when the function IsFurry is called since that function does not exist at that memory location.

The dangers of C++ string literals and non-const pointers

Foreword: I originally gained insight into this issue from Pete Isensee's blog post "When it Rains".

For years I used to take this line of C++ code for granted:

const char* str = "abcdef";

However, const protects you from altering the defined string literal values which is a good programmer habbit.

Question:
Why is this important, and why do most programmers use it?

Answer:
It's very important because according to the standard 2.13.4/2 "the effect of attempting to modify a string literal is undefined"

Question:
What is the correct way to alter strings?

Answer:
If you want to dynamically change string values use a character array because it creates a copy of the string. Moreover, the character array will terminate nicely with the null character '\0'.

Correct declaration and defintion:
char str[] = "abcdef";

Don't do this because it is undefined:
char* str = "abcdef";
str[0] = 'k';

Do this instead:
char str[] = "abcdef";
str[0] = 'k';

C++ post and pre-increment operator overloading does not behave like intrinsic type operators

//C++ post and pre-increment operator overloading does not behave like intrinsic types
//Version: 1.00

#include <iostream>
using std::cout;
using std::endl;
using std::ostream;

class IntWrapper
{
  friend ostream & operator<<( ostream&, const IntWrapper& );

  public:
  IntWrapper( int val = 0 ) : i(val) {;}

  IntWrapper operator+( const IntWrapper& rhs) const
  {
    //use RVO
    return IntWrapper( this->i + rhs.i );
  }

  IntWrapper& operator++()
  {
    ++this->i;
    return *this;
  }

  IntWrapper operator++(int)
  {
    IntWrapper tmp(*this);
    this->operator++();
    return tmp;
  }

  private:
  int i;

};

ostream &operator<<( ostream &, const IntWrapper & );

int main()
{
  //interesting results of the post and pre increment operators

  IntWrapper test;
  int i = 0;

  IntWrapper test1 = test + test++;
  int test2 = i + i++;

  //test1 should be the same as test2 but they are not

  cout << test1 << " for intrinsic types test1 should be the same as test2 but is not since they are not intrinsic types " <<
  test2 << endl;

  cout << i << i++ << test << test++ << endl;

  system("pause");
}

ostream &operator<<( ostream &output, const IntWrapper &r )
{
  output << r.i;
  return output;
}

The conclusion to this experiment is that due to the unspecified behavior according to clause [5/4]
of the standard the assumption that overloading post and pre increment operators will behave in the same manner as the intrinsic type operators is incorrect and not waranted by the standard.