Category Archives: Computer Science

testing, casting & implicit conversion, and methods vs functions

This past week in OOP we discussed how to test private and protected members of a class in C++ without having to change the implementation, casting and implicit conversion and how to turn it off in C++, and we looked at methods vs functions.

The first discussion was motivated by the project which was due on wednesday and the fact that it is nice to be able to test internal state but many of the solutions involved making the class a friend of the tester which required some work and portrayed an object model that was not entirely true, and furthermore might need maintenance in the future. The better solution was to use compiler directives to expose all of the members and as such the state, the code for which would look something like:

#define private public
#define protected public
#define class struct

#include "darwin.h" //the header file we wanted to include in the tester

With reference to casting we covered the fact that in C++ we can typecast an int to a double, which we can also do in Java, however we can also typecast a double to an int(with a loss of precision) which we can’t do in Java. Prof Downing also introduced that fact that the one arg constructor was an implicit conversion function from the type of the argument to the type of the object, in some cases though this is undesirable so by defining the constructor with the keyword ‘explicit’ we can force this implicit conversion to not happen, we then sacrifice the nice syntax of <Type> x = <value>; and we are forced into using the otherwise equivalent <Type> x(<value>); syntax. In C++ we can additionally define functions for other types to allow conversion of the user defined type to the other type, the syntax for which is as follows:

operator <some_type_here>(){...} //will always return a value of type <some_type_here>

In cases where these implicit conversions might cause problems the compiler will prefer the non-converted function.

Progressing through the list we come to the comparison of functions vs methods and when to use which. Functions belong to no class or rather they exist in the file/global scope whereas methods are bound to a class. Methods normally my first choice coming from Java but when deciding which to use one should ponder the following questions: “does the public interface provide all the access we need to perform the function?”, “do we need to define the operation with a different class on the left hand side(example: ostreams’  << and  istreams’ >> operators)?”, and “do we want the operation to be symetric?”. If you answered yes to any or all of the above then it might be worthwhile to define the code block as a function(using friend if necessary).

Advertisements

Heap Emulation

This week in OOP we began focusing on type casting in C++ as well as allocation strategies and data storage strategies.

The type casting of C++ is a bit more verbose than it is in most other languages, the reason being is that often when typecasting data is truncated and latter we find that this data was needed, so since errors sometimes result C++ has taken to making typecasting easy to spot by giving it an overly verbose form. An example of this is the following:

int& view(char& c) const{
return *reinterpret_cast<int*>(&c);
}
 

The allocation and data storage strategies we reviewed were the following:

  • in C++ most systems interpret a char as 1 byte, as such it is a lightweight way to store general byte data.
  • to denote free space in a heap we can create sentinel values as int values(aka: 4 bytes), often these values might get overwritten accidentally, so to provide some minor error checking store two copies of each sentinel required.
  • to denote active/taken blocks use a negative value to distinguish between free blocks(positive values)

By using this information as well as some unit tests developed on the native heap manager we hope to achieve a similar heap manager that allows us more granular control of the data it has allocated, this is stricly for educational purposes of course.

performance and backing of data structures and c++ iterators

In the days that lead up to the test I found that most of my time was spent trying to chase down an off-by-one bug and in class brushing up on data structures and iterators. The earlier problem was resolved by spending roughly 5 hours running through the code inserting statements to help us see how the code was breaking and then exploring how to get GDB working with the eclipse CDT plugin. The latter was an exercise in note taking.

To recap the 5 common C++ iterators and the operators they provide are:

  • Input: !=, ==, *(read only), ++
  • Output: *(write only), ++
  • Forward: all of input’s and it can read or write on *
  • Bidirectional: all of forward’s and —
  • Random Access: all of bidirectional’s and [], +, -, <, >, <=, >=

As such if you want to make a method which accepts the most iterators you should only expect the operators provided by input or output and no others. However, < tends to be more robust as it will terminate in the case of the begining and the end iterator getting mixed up where inputs != won’t.

In the data structures discussed we looked at cost of selecting, removing, and adding elements which belong to various structures…. most of this discussion was review to me but the discussion continued to the different underlying data structures that could be used to build stacks, queues, and priority structures and this was something that I had not thought about. In summary the subcomponents were vectors, linked lists, and tree structures and stacks can use any of these, queues can use any but vectors, and priority queues can use any but linked lists.

Exceptions, Pointers, and Reference

As my weeks seem to grow increasingly short I find myself this week between interviews and assignments brushing up on some of the old lecture notes from the classes previous two weeks in the hopes that I will be ready for the test. I felt in terms of value the last week has been one of the more enlightening in terms of long term impact. The focus had been on Exceptions and C++: pointers, and references.

Exceptions had been mostly a review but I found several fine points which I had yet to encounter. One of the first points was that in Java you can catch the exception if the heap/stack overflows where as C++ there is no nice way to do this. Another point that I hadn’t considered was in the case that you caught an exception but found you couldn’t handle the exception, in this case you can re-throw the exception caught and it will propagate up the call stack until the same exception is caught in the callers.

On the pointer/reference side of things I had always found that these constructs had been the source of many a bug in my code so it was nice to go through them again. The highlights were:

  • pointers can have the address they point to changed references can not(although both can have the value they point to changed if it is mutable)
  • pointers must be dereferenced(use * to access the value they point to rather than the address) to have there value manipulated where references do not need to be dereferenced
  • references are useful as aliases in the same function scope this does not serve much purpose but this proves useful to abstract out the complexity from the programmer in function argument passing(as compared to pass by pointer)
  • non-dynamic arrays are much like pointers, in fact you can dereference the pointer and select its zero-th value to prove this, however the sizeof function will return the total size of a non-dynamic array where as it will only return the size of the pointer argument on a dynamic array/pointer. In addition the allocations of the stack(non-dynamic arrays) must only have one name for the reference.
  • dereferencing the array + n is the same as a[n] if a is the array(aka: *(a+n) == a[n] for all integer values of n in which n is less than  the array length)