Menu
Home
Log in / Register
 
Home arrow Computer Science arrow Learn BlackBerry 10 App Development
< Prev   CONTENTS   Next >

Polymorphism

We defined the Stock and Option class, but for our class library to be truly useful, we need to be able to manipulate them using the common base class Instrument interface. In practice, we care about being able to price instruments no matter the concrete type; whether it is a Stock or an Option. In other words, we want to be able to manipulate financial instruments using the base class Instrument abstraction. If the instrument is a Stock, it will return its market spot price, and if it's an Option,

it will return the Black-Scholes price. This is exactly what we imply by polymorphism: the ability to implement the pricing logic differently depending on the underlying concrete type and being able to call at runtime the correct implementation using the Instrument base class abstraction. In C++, runtime polymorphic behavior is achieved using two mechanisms: references and pointers.

Using References

A reference is essentially an alias to an existing variable. Listing 3-10 shows you how to use a reference when pricing an option.

Listing 3-10. Using References

Option option; option.setOptionType(Option::CALL); option.setSymbol("myOption"); option.setSpot(50); option.setStrike(55); option.setTimeToMaturity(0.5); option.setRiskfreeRate(.05); option.setVolatility(.2);

Instrument& instr = option;

std::cout << "Instrument symbol is: " << instr.symbol().toStdString() << std::endl; std::cout << "Instrument price is: " << instr.price() << std::endl;

As shown in Listing 3-10, instr is defined as a reference to an Instrument by adding an ampersand (&) after the type declaration (note that because a reference is an alias to an existing object, the definition must also include the referenced Option object). Finally, the price() method is called polymorphically using the Instrument base class interface (remember that price is a pure virtual function in Instrument's class definition). The program's output is given as follows:

Instrument symbol is: myOption Instrument price is: 1.45324

Another way of using references is by taking them as function parameters. For example, Listing 3-11 defines a showInstrumentPrice() function taking a reference to an Instrument (note the & indicating a pass-by-reference of the instrument parameter).

Listing 3-11. showInstrumentPrice

void showInstrumentPrice(const Instrument& instrument) {

std::cout << "Instrument symbol is: " << instrument.symbol().toStdString() << " Instrument price is: " << instrument.price() << std::endl;

}

int main(){

Stock stock; stock.setSymbol("myStock"); stock.setSpot(50);

Option option; option.setOptionType(Option::CALL); option.setSymbol("myOption"); option.setSpot(50); option.setStrike(55); option.setTimeToMaturity(0.5); option.setRiskfreeRate(.05); option.setVolatility(.2);

showInstrumentPrice(stock); showInstrumentPrice(option);

}

The showInstrumentPrice function takes a reference to an Instrument object. It does not know if the actual object is a Stock or an Option, but it knows that it can call the base class

Instrument::price() method in order to get the instrument's price. Because Instrument::price() has been declared as virtual, the C++ runtime determines the correct price method to call using virtual function dispatch. The output of the application is given as follows:

Instrument symbol is: myStock, Instrument price is: 50 Instrument symbol is: myOption, Instrument price is: 1.45324

In other words, the Instrument::price() call is polymorphic and returns a different price depending on whether you pass a Stock or an Option. This only works because you are passing a reference

to the showInstrumentPrice() method. If you try to change the showInstrumentPrice signature by removing the reference operator to showInstrumentPrice(Instrument instrument), the C++

compiler will try to pass the Instrument parameter by value. The value semantics imply that a copy

of the variable is passed to the function. The copy operation is done by calling a copy constructor, which is a special class constructor used for making a copy of a class instance. If you don't specify a copy constructor, the C++ compiler will generate one implicitly for you, which will do a memberwise copy of the source object.

There are several reasons why this will not work in the previous case:

n As explained, the compiler will try to generate a copy constructor. However, because Instrument is an abstract class, the C++ compiler cannot generate a copy.

n Let's suppose that Instrument did provide a default implementation for the price() method, always returning 0. Something more serious, called object slicing, would occur: only the base Instrument part of the object, whether it is a Stock or an Option, would be copied and passed to the showInstrumentPrice() function (the overridden price method would therefore be “sliced-off” and you would lose all polymorphic behavior. In other words, the function call would always return 0, no matter the concrete type passed to the function).

n There is a third reason why you can't pass an Instrument instance by value: Instrument's base class is QObject, which does not support value semantics. (I will tell you more about value semantics when we discuss QObject identities. For the moment, suffice to say that because a QObject's copy constructor is private, you cannot use it in order to make a copy of the class instance.)

Using Pointers

Now let's look at how polymorphism can be achieved using pointers. Listing 3-12 gives you an updated version of the test application using pointers (in other words, the objects are dynamically allocated on the heap).

Listing 3-12. Pointers

Stock* stock = new Stock; stock->setSymbol("myStock"); stock->setSpot(50);

Option* option = new Option; option->setSymbol("myOption"); option->setSpot(50);

option->setStrike(55);

option->setTimeToMaturity(0.5); option->setVolatility(.2); option->setRiskfreeRate(.05);

Instrument* instrument; instrument = stock;

std::cout << "Instrument symbol is: " << instrument->symbol().toStdString() << std::endl;

std::cout << "Instrument price is: " << instrument->price() << std::endl;

delete instrument; instrument = option;

std::cout << "Instrument symbol is: " << instrument->symbol().toStdString() << std::endl; std::cout << "Instrument price is: " << instrument->price() << std::endl;

delete instrument;

This time we allocate the Stock and the Option on the heap using the new operator, which returns a pointer to the dynamically allocated object (in all of the examples until now we were allocating automatic objects on the stack). We also use an Instrument pointer (Instrument*) in order to

polymorphically call the price method, which is resolved at runtime. The program's output is given as follows:

Instrument symbol is: myStock Instrument price is: 50 Instrument symbol is: myOption Instrument price is: 1.45324

Also note that the objects must be deleted when no longer needed, otherwise you will face a memory leak. This concludes our condensed overview of C++'s OOP features. The next sections will further concentrate on the Qt extensions to C++.

 
Found a mistake? Please highlight the word and press Shift + Enter  
< Prev   CONTENTS   Next >
 
Subjects
Accounting
Business & Finance
Communication
Computer Science
Economics
Education
Engineering
Environment
Geography
Health
History
Language & Literature
Law
Management
Marketing
Philosophy
Political science
Psychology
Religion
Sociology
Travel