Monthly Archives: April 2007

C++ for ObjC programmers Part IV: Classes

Instead of providing a toy example, I figured I will just annotate an existing open-source C++ class. I will talk about a class in the Synthesis Toolkit(STK). I don’t talk about actually implementing classes much, so that’s for next time. Also, I haven’t compared ObjC code to C++ code since the Part I, so I will probably do that next time.

I. Basics

Let us take a look at the existing Instrument class in the Synthesis Toolkit, which is a set of libraries written in C++ for audio signal processing and computer music. Here’s the link to the file I will be talking about –> source file link.

Taking it from the top. Remember that Flute.h is analogous to the @interface file in ObjC.

00025 #ifndef STK_FLUTE_H
00026 #define STK_FLUTE_H
00027
00028 #include "Instrmnt.h"
00029 #include "JetTable.h"
00030 #include "DelayL.h"
00031 #include "OnePole.h"
00032 #include "PoleZero.h"
00033 #include "Noise.h"
00034 #include "ADSR.h"
00035 #include "SineWave.h"

This illustrates a classic C++ idiom. One of the few places that preprocessor directives are essential is to avoid multiple header file inclusion. The directives above say that if the symbol STK_FLUTE_H is not defined , define it and include all those header files only if STK_FLUTE_H is not defined. #endif closes the #ifndef STK_FLUTE_H block. In Objective-C(with Apple’s developer tools), one always uses #import “headerfile.h” which automatically safeguards against multiple inclusion of header files.

00037 class Flute : public Instrmnt
00038 {
00039 public:


00079 protected:
00080
00081 StkFloat computeSample( void );
00082
00083 DelayL jetDelay_;
00084 DelayL boreDelay_;
00085 JetTable jetTable_;
00086 OnePole filter_;
00087 PoleZero dcBlock_;

The protected keyword indicates that the following functions and variables will only be public to this class and the classes that inherit from this class.

00047 ~Flute();

This is a destructor: You put all your dynamic memory deallocation here, but never call this function from your own code as it gets called automatically. Remember auto_ptr<T>? I wouldn’t be surprised if the way it worked is: The memory to which the raw pointer points to is deallocated when the smart pointer’s destructor is called automatically—remember the raw pointer is “wrapped” by the smart pointer.

It turns out for the particular Flute class there is no dynamic memory allocation, so the destructor is empty(I looked at the implementation file).

In case the StkFloat and DelayL above were confusing you, they are nothing but user-defined types(either user-defined classes or typedef aliases–more on typedef later).

II. Inheritance

There is more to know about classes, but let us discuss the important topic of inheritance. Remember the “IS-A” relationship. So, a flute “is-a”(n) instrument. This might seem obvious and unnecessary, but here we are looking at models of physical instruments. Thinking a little about “IS-A” and “HAS-A”(“HAS-A” is used for composition, which is essential in the ObjC-based Cocoa framework, possibly more on this later) will go a long way in helping us design classes when we are modeling more abstract entities.

Let us briefly take a look at the “parent” class of Flute, Instrument(if you download the source code for the STK framework, you can find Instrument.h and Instrument.cpp(Instrument.cpp is analogous to @implementation). I will talk about Instrument.h available here.

class Instrmnt : public Stk
00018 {
00019 public:
00021 Instrmnt();
00022
00024 virtual ~Instrmnt();
00025
00027 virtual void noteOn(StkFloat frequency, StkFloat amplitude) = 0;

What is this virtual business? Here’s a concise description:

Within the C++ the virtual keyword identifies to the compiler that a class function may be overridden in a derived class. That is, the derived class may supply a function of the same name and argument list, but with different functionality defined in the function body.

from this link. Now, note that virtual void setFrequency(StkFloat frequency);
has a function body in Instrmnt.cpp while virtual void noteOn(StkFloat frequency,...) doesn’t. If a function body existed, it would have been found in Instrmnt.cpp. This lack of a function body is indicated by the = 0 at the end in Instrmnt.h . Why would someone not have a function body and actually declare the function? Answer: To capture the commonality of all the classes that will be derived later from the base class, so that the user might do something like this:

//Warning: untested code just used for illustration purposes
Flute flute(440.0); //some made up lowest frequency 440.0
Clarinet clarinet(450.0);
vector < Instrmnt > instrumentlist;
instrumentlist.pushback(flute);
instrumentlist.pushback(clarinet);
vector< Instrmnt > instrumentlist::iterator pos;


for(pos = instrumentlist.begin(); pos != instrumentlist.end; ++pos)
{
pos->noteOn(440.0,200.0); //contrived values

post->noteOff(50.0); //contrived value 50.0

}
Also observe that it doesn’t make sense for a generic instrument to have a noteOn function, but it does make sense for the derived classes like Flute. Note that I’m treating both flute and clarinet as instruments in the above code, which enables me to write better code, instead of handling each type of instrument in a switch statement of if-else if-else construct.

III. Virtual Destructors:

Finally, let us talk about virtual destructors. Here’s a rule of thumb from Scott Kleper and Nicholas Solter(authors of Professional C++):

Always make your destructors virtual

I would qualify that with make your destructors virtual when necessary(obviously the STK authors don’t make destructors virtual when not necessary). Suppose for a moment that Flute and Instrmnt had dynamically allocated memory, so that both the Instrmnt and Flute destructors had important deallocation code, and I had the following situation:

int main()
{
Instrmnt* instr = new Flute(440.0);
delete instr;

return 0;
}

This would call Instrmnt’s destructor and not Flute’s destructor(since I didn’t make Flute’s destructor virtual). If I had, I wouldn’t have the problem.

IV. Postscript
This is just the tip of the iceberg when it comes to talking about C++ classes. You will find more information in Bruce Eckel’s Thinking in C++ Volume I, or Professional C++ by Nick Solter and Scott Kleper

Existing screencasts uploaded to ShowMeDo

I have found that this is probably the most convenient site for users as they don’t have to download anything(you can if you want), but the streaming flash version works just fine.

Anyway, here’s the link: (The screencasts are the ones I previously announced, they are just also available at ShowMeDo)

A Basic RubyCocoa tutorial

I have uploaded a pdf file in the blue Box widget to your left. The pdf file is called rbcocoa.pdf. Drop me a comment if you can’t see the Box widget for some reason(recent versions of Safari, Camino and Firefox should display it fine)

The document is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 license

Disclaimer stuff:

5. Representations, Warranties and Disclaimer

UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND ONLY TO THE EXTENT OF ANY RIGHTS HELD IN THE LICENSED WORK BY THE LICENSOR. THE LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MARKETABILITY, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.

6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

Nice utility

http://www.donelleschi.com/stickywindows/

Nice Very nice window management app(found this through MacResearch).

C++ for ObjC Programmers Part III: Smart Pointers

Update(May 20, 2007) — I have posted a short introduction to Boost smart pointers here.

Please Note: Smart pointer implementations other than auto_ptr<T> often use reference counting mechanisms(yes the reference counting mechanism is analogous to what you see in ObjC). I don’t talk about reference counting in C++ in this article, but I will probably talk about it in the future. I can point you to the freely available source code from the book Professional C++ here. This code demonstrates a reference-counting smart pointer implementation. I might make a few comments on the code later.

In Part II, I talked about some of the ways in which C++ differs from C. One of the complaints against C++(and C) is its manual memory management. The problems with manual memory management can be mitigated with the use of smart pointers and eliminated with a third-party garbage collector. However, garbage collectors introduce some overhead, and one has to download and ‘install’ the library. The built-in smart pointer class, auto_ptr<T> is not the fastest or best implementation of smart pointers, but it is “close enough for government work”. I probably said that I will go through the creation of classes in this iteration, but there are few C++ resources which talk about smart pointers and many that talk about class construction, so I will go through smart pointers first

There is nothing magical about smart pointers. If one understands how the stack and the heap work, then the basic premise behind smart pointers is easily understood. Here is my quick overview of the stack(Try Wikipedia for an overview of the heap for now)

(Warning: conceptual material ahead 🙂 Skip to the code if bored/confused.

The stack and the heap are two different buffers(set of memory locations in RAM). Programmers specify what will go on the stack when they actually write the program. For example , when you say int x = 0; you are adding the variable x to the stack(actually to the function’s activation record(aka stack frame), which is on the stack). What is an activation record? When I call a function say, for example z = sum(x,y), an array of information is pushed onto the stack, including, (but probably not limited to) the function parameters, local variables, and return address. Here’s a nice picture(note that the stack “grows” to the bottom). The “ESP” denotes the stack pointer, which points to the “top” of the stack. i, j, and k are the parameters to the function. This picture shows how the stack looks like immediately after the function is called.

activation record example

After the function starts executing , there has to be space for local variables:

Second Picture

Pictures courtesy of this link

So, the local variables are a, r, c, b, and w. After the function does its work, the activation record is “popped”. Okay, the old locations of a, r, c, etc. might still be the same for a short while after the activation record is popped, but the programmer is not supposed to try and use those memory locations after a function returns–because there might be another function’s local variables using the same memory locations. “Popping the activation record” is done by moving the Stack Pointer, ESP back to the top of the grey box(Previous Stack Contents).

Okay, how is this related to smart pointers. The scope of a local variable is the function in which it is defined. So an easy way to think about this is if you have a function foo:

int foo(int x, int y)

{

int one;

/* calculations here */

return one;
}

Then once the statement return one; is executed, and the } is reached, the activation record for foo(..) is popped. So a smart pointer works by “wrapping” a regular pointer inside a stack based object(the auto_ptr). Then when an auto_ptr smart pointer object is “popped”, the dynamically allocated memory which the “dumb pointer” points to is automatically deallocated , ostensibly by automatically calling delete on the dynamically allocated memory pointed to by the “dumb pointer”.

—END of potentially boring conceptual/background material———-

Here’s some code that shows how to use a smart pointer.
#include <iostream>
#include <vector>
#include <string>
using namespace std;

int main()
{
string* new_str = new string(“hello world”);

//important line
auto_ptr < string > smrtstr(new_str);

cout<<“The string length is”<<smrtstr->length()<<endl;
return 0;
//no need to call delete or anything.
}

Now, if you plan to use smart pointers for a real project, you should invest some time to install the Boost smart pointer library (the auto_ptr has some issues when dealing with Standard Template Library containers like vectors, maps, etc)

Good data structures resource(many programming languages)

Dr. Bruno Preiss’s book

C++ for ObjC Programmers: Part II

In Part I, I talked about the differences between static typing and dynamic typing. I previously said I won’t be able to cover C++ from the very basics. However, for those who already know C, I can give a whirlwind tour of C++. This post is a shorter one,but hopefully useful.

1 Highlights

1.1 Some differences from C
  1. Including headers: #include<iostream> as opposed to #include <iostream.h>
  2. Reference parameters instead of “Pointer parameters”: In a C swap function, you would have:void swap(int *x, int *y)
    {
    int temp = *x;
    *x = *y;
    *y = temp;
    }In C++, you would use reference parameters. You would implement swap as follows:
    void swap(int &x, int &y)
    {
    int temp = x;
    x = y;
    y = temp;
    } Here, the & symbols in front denote that the addresses, and not the value of the parameters is passed in, so the original variables(and not copies of the variables) are modified. You can also define standalone references(although this is not widely useful). You can do
    int t = 0;
    int &tref = t;
    tref++; //changes t
  3. You do not have to use preprocessor directives like #define PI 3.14159. Much better is the use of true constants like const float PI = 3.14159; You can also use enum(I have a post on enum), but usually the const float PI method is more convenient.
  4. Use inline functions instead of the dangerous macro function expansions. The compiler can choose to ignore you if it thinks the function is better left as a real function(trust the compiler if you set the optimization level high!). Example of inline function:
    inline square(double x){ return x*x;}.
    Note that this is not inline because I put it all in one line, but because the compiler “search/replaces” all function calls to square in our other code by x*x if it decides to follow our guideline. WIth inline functions, you tradeoff better performance for an increase in code size.
  5. Pointers can be used just like in C. However, when working with the STL(Standard Template Library), one often uses iterators instead of pointers.
  6. Use new and delete rather than malloc and free for dynamic memory allocation. New and delete are much easier to use, and C++ programmers can bid malloc and free a “fond farewell”–Scott Meyers. Example:int *int_ary = new int[100];
    /* more code here */
    delete[ ] int_ary; The above snippet was for dynamically allocating an array of ints(same type of syntax for array of objects). What if we just want to dynamically allocate just one object? Example:int *ptr = new int; delete ptr;

Next time: basics of C++ classes, inheritance, polymorphism, virtual functions, and smart pointers.

Meanwhile, other C++ resources: C++ Reference, Cplusplus.com (this last one is not necessary the most accurate source, but useful for a quick reference).