Monthly Archives: April 2012

abstract classes and methods, Life, and function binding

This week in OOP we talked about approaches to the Life project, function bindings and how to use non-default bindings in C++/Java, and abstract methods and classes.

When we talk about function binding we are referring to the function that is invoked. The bindings that we have studied this past week are dynamic and static binding, with static binding the declared class of the object/variable is the function that is invoked, with dynamic binding the type of the value that is stored in the variable or the type of the object itself determines the function that is invoked. As you might have guessed by now java uses dynamic function binding by default and C++ uses static by default. However either can have the opposite binding enabled by keywords in Java this is accomplished by the use of private methods, static methods, final methods, or final classes. In C++ dynamic binding is enabled by using the keyword virtual on the parent method, this will cause a look up table to be built and used at runtime to determine the function to be invoked.

Java has the convention that either a class can be abstract and have no abstract methods or it must be abstract if any methods are abstract. As such disallowing instantiation of the class and all subclasses that choose to not implement the abstract methods. If a method is declared abstract then it can’t have an implementation as such you end up having to create protected helper methods if desired with different names. As you might imagine C++ is a slightly different story, you can have abstract(/pure virtual) methods but they may have implementations if you choose to provide them, however the methods must be implemented in function scope. The notion of an abstract class with no abstract methods does not exist in C++ however a pure virtual destructor would give you much the same result.

overloading, functions vs. methods, and rule of three

As we progress through the semester, and a fast approaching third test we find ourselves focusing on overloading, functions(symmetric operations) vs methods(asymmetric), and the rule of three.

    when overloading functions or methods in C++ there are several values that can be overridden. for functions we have: the types of the arguments and if the function is not an operator then we can also override on the number of arguments. Likewise with methods we can override on the type of the arguments and the const-ness of the method, if the method happens to not be an operator then we can also override on the number of arguments as well.

   In designing a class one of the questions that should be asked is whether the function could/should belong to the class which members it would need to take as an argument. To answer this question we can look at the constructor and if it is not marked explicit(as such allowing implicit conversion from the type of argument it accepts) then we should allow the function to remain outside of the scope of the class, this way we can have the implicit conversion for its arguments happen on either side. In addition to the last mentioned sided-ness argument one should also consider if the left hand side of the function needs to be of another class (for example the input/output streams) if this is the case then we again want to keep the function outside the scope of any class as we cant modify the stream class directly, so we let the globally scoped function do the work for us. Otherwise it might be appropriate to declare the function as a method instead.

 The rule of three was another topic covered and it quite simply says that if we need to override any of the destructor, copy constructor, or the copy assignment operations then we will likely need to override the other two of the ones mentioned above. To do this without repeating code we could create helper methods or we could define the copy constructor in terms of assignment or the assignment in terms of the copy constructor, the latter if probably more favorable as it leads to a three line solution involving calling swap.

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).

darwins game of life

As the semester is rapidly coming to a close I find myself still learning new lessons in OOP. Namely what the funky syntax is that I note on some constructors (initializer lists) and that I don’t fully understand the STL data structure.

When programing we like to have certain data be available to all of the instances of a class but have only one copy, in java this is easy, simply declare a static variable. In C++ the static variables exist but they operate in a slightly different way, namely they are ‘flavor’ or class specific so a subclass has a different static variable than the superclass. In C++ if you want the static instance to be nonchanging then you can declare it final and use the syntax <class>(<params>) : <name_of_static_final_var>(<value/variable>) { <other assignments and such>} this will have the net effect of assigning the variable/value to the static var. In java you can use static initializer blocks to do a rough equivalence to this.

In working with the STL libraries my partner and I ran into an interesting issue, we wanted the board to store the creatures and we wanted to be able to move the creatures easily, as well as not have a state explosion if the population of valid creatures was small(as it normally is with respect to the board). So our first approach was to make a vector for storage and use the pointers to the elements of the vector, however after much frustration we realized that push_back can cause the vector to grow and it might but will not always change the addresses of the elements. What was curious was that on a 32 bit machine all was well, on a 64 bit machine we failed some unit tests, however if we ran the program in valgrind everything worked fine. This goes to show that some compilers helping you out can cause a lot of frustration in the long run because they effectively mask the real problem at play.