Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

C - C++ Transition 2

Status
Not open for further replies.

manvid

Programmer
Apr 1, 2002
37
0
0
IN
I consider myself to be a decent C programmer and I started to learn c++/Object Oriented Concepts sumtime back.
I have done a reasonable amt of c++ coding .. using fundas like inheritance/polymorphism etc. the ? is where/when are concepts like virtual functions/templates/abstract classes used? I have a vague idea abt them, but iam unable to comprehend its usage...
 
Hi,
Let's take example of factory design pattern .. I hope you are aware of design patters ... in that, we actually use the virtual functions and abstract class. Base class has the virtual functions which are to be implemented in derived classes. If you declare some function and assign it to zero then it becomes pure virtual function. The class which has such pure virtual functions become abstract class. Since, it has pure virtual functions, you can not instantiate the object of it. So, you need to derive another class from it and implement all the pure virtual methods of it.
As far as template is concern .. take an example of link list... since you are more comfortable with C programming .. if you want to have link list with single data say integer. But, tomorrow if you plan to have float instead of integer ... then you will have to change the entire stuff .. from integer to float. Similarly .. if you want to use class A and then may change to class B .... which is possible. In this case .. instead of hardcoding the datatype .. you declare some sort of place holder which is called as template. In C++, we have standard template library .. which includes vector, list, map etc.

hope this helps.
regards,
Mahesh
 
Moreover, the whole idea behind all of these methods is re-use of code... It'll take a little longer to get the class going the first time, but after that you can re-use the code over and over.

virtual functions are best when you want to have an array of assorted objects at once... All you need is a base class, and you can run through the container calling a function (say f()) of different classes, regardless of if f is of class A or B.

For instance, lets consider this:
you have a container (an array/linked list what have you) of BASE pointers, that point to objects derived from base that are either DER1 or DER2... each have the function f() (which was declared pure virtual in the base) and have overriden it.
Code:
//BASE.h
class BASE
{
public:
...
Code:
virtual void f()=0;
...

Code:
class DER1
{
public:
  virtual void f(){/*some stuff*/}
}
...

Code:
class DER2
{
public:
  virtual void f(){/*some other stuff*/}
}
...

Code:
//main.cpp
//after assigning the pointers to objects of DER1 and DER2
for(size_t i = 0; i < size; i++)
{
   container[i]->f(); 
   //for objects of type DER1, this will call DER1.f()
   //for objects of type DER2, this will call DER2.f()
}

Note: The BASE class is abstract, and you cannot declare objects of BASE type, but you can have pointers of the BASE type pointing to derived objects...

Factories, Singlton and the like are very useful.

Templates are just as Mahesh has discribed. The best example of usefulness is the STL... For instance, look at the vector.
Code:
vector<int> INTS(3,5);
vector<char> CHARS(100,'a');
One time writting the class, no need to edit the vector.h or vector.cpp to make it use ints or chars, just use it's template. Usefule STL stuffs:
- map (hashtable data type, required a comparison function lessthan or operator < (can't remember which))
- set (binary search tree, same requirements as MAP)
- vector (Dynamic array, any first class object or data type)
- list (linked list, any first class object)
- stack (see vector)
- deque (see list)
They come with nested templated interators, and the STL has an algorithm library for easy ability to sort, remove duplicates and any other common container operation... Templates and the STL make life REALLY easy.
 
I don’t think I would agree that the whole idea is about re-use. That can be beneficial and you certainly want to take advantage of it whenever possible. I think the more significant benefits are loosely coupled designs that achieve highly flexible, extensible and maintainable applications.

The growing adoption of Software Patterns in the past few years has resulted in an abundance of online information about them. You should probably check some of this out. I can’t say for sure if it would help you grasp the OO concept more readily but it’s worth a go I think.

One classic example of a loosely coupled design is a drawing program with a Shape interface. The idea is the Shape interface defines a Draw() method that maybe takes a parameter we might call Canvas. The Canvas class contains all primitive drawing methods and encapsulates the computer graphics system being used. Now say you implement several concrete Shape derivatives ( Square and Circle) and release your application. Now several years later you can add new concrete Shape derivatives, Triangle and Cube and your Canvas and it’s underlying graphics operations are completely unaffected. Also unaffected is your UI code that allows the user to drag and drop these concrete Shape objects from a tool window, since all the UI classes see is a &quot;Shape&quot;.


-pete
 
Hi,

Pete has given a very basic and good example to understand the factory pattern. Here from factory you wil get either circle or square or some other shape as shape object i.e. base class. All these different shapes will implement all the virtual methods defined in base class i.e. Shape. So, the factory interface will instantiate either circle or square or any shape depending upon the request and will return it as shape object.

regards,
Mahesh
 
To see the benefits of Pete's shape example, consider implementing it without inheritance and virtual functions (i.e. essentially a C version).

You'd have to have something to the effect of a case statement wherever an operation needs to be done on a shape (including creating one) and that operation depends on the type of the shape.

In that case, adding a shape to your application would involve tracking down all those case statements and adding an extra entry for your shape. This is tedious and error prone, and it's bad design since the information about each shape is spread throughout your application code, which means all that has to be recompiled when you add the shape.


A slightly better version would be to put those case statements in a set of functions related to the shape object (or member functions of a Shape class) and put all those in a singe source file. That centralizes all the Shape information and keeps you from having to recompile anything but that one compilation unit when you add/remove a shape. It's still not very good, though, since adding a shape means you have to recompile all other shape code.


Using a base class and virtual functions allows you to centralize the logic for each shape in its own class, and keeps you from having to recompile all the other shapes when you add or remove or change one.


The idea of abstract base classes is not necessary to achieve this kind of low coupling, but the idea is that an abstract base class contains an interface and nothing that should ever need to be recompiled. Since that class can never be changed, you should theoretically never have to recompile any code that uses it, yet by writing other derived classes to conform to that interface, you can essentially add functionality to that code without recompiling it.
 
Just to clarify, the Shape etc., example is a classic one that i have read time and time again in articles and books. So it's not mine other than i brought it up in this thread. ;-)

Anything that i know that is good I learned from someone that came before me. Anything i say that is wrong i probably thought of myself [lol]

-pete
 
A word on templates:

Templates were designed to be used for generic programming, a concept that's separate from OO (but can still operate well with it). In their simplest form, they can be used as Mahesh describes: as a way to code a data structure once, and generate classes from that template that differ only in the type of data they can contain.

A more generic way to think about templates is as enablers for &quot;compile-time polymorphism.&quot; A function template can operate on any data type that follows the &quot;concept&quot; expected by that template (i.e. supports all the functions and operators the template tries to use on it, etc.). This allows you to use a single &quot;function&quot; on multiple data types as long as they have the correct &quot;interface.&quot;

An example is the generic algorithms provided in the STL. The find algorithm expects a range represented by two iterators and a value to find. As long as something supports the iterator interface, you can pass it into the find function. Hence, you can give it iterators to a vector, a list, a hash table, an input stream, or even a plain old C array and have it operate equally well on all of them.

You'll notice templates have a function similar to that inheritance and polymorphism: you can use the same function to operate on very different types of data and get a different effect based on that data.

The main difference is in when this is accomplished. Virtual functions &quot;choose&quot; their mode of operation at run time. Thus, when using virtual functions, your program runs slower. Templates &quot;choose&quot; their mode of operation at compile time. This results in a bigger executable and longer compilation times, but faster runtime operation. This is why I referred earlier to using templates as &quot;compile-time polymorphism.&quot;

Note that though templates and polymorphism can be used to solve similar problems, they aren't interchangeable. Experience will show you what problems templates are most suited for and which ones should be solved by polymorphism.

A lot of design decisions involve choosing between templates and polymorphism; sometimes, you can use both to good effect. As an example, check out the C++ iostreams library. It's an elegant design that balances the use of templates and inheritance to create a type-safe, easy-to-use, and extensible I/O system.

Finally, be aware that templates can be used for much more complex things than you'll probably encounter anytime soon. They're essentially an entire metaprogramming langauge unto themselves.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top