Abstract Data Types - Separating Interface from Implementation

A

Anon Email

Hi people,

I'm learning about header files in C++. The following is code from
Bartosz Milewski:

// Code

const int maxStack = 16;

class IStack
{
public:
IStack () :_top (0) {}
void Push (int i);
int Pop ();
private:
int _arr [maxStack];
int _top;
};

--------------
// Header file

#include "stack.h"
#include <cassert>
#include <iostream>
using std::cout;
using std::endl;

//compile with NDEBUG=1 to get rid of assertions

void IStack::push (int i)
{
assert (_top < maxStack);
_arr [_top] = i;
++_top;
}

int IStack::pop ()
{
assert (_top > 0);
--_top;
return _arr [_top];
}

--------------

I know this is very basic code. I also know that it's a non-standard
header filename/ file. I'm merely using this for demonstration
purposes. Let's pretend that in C++ it's possible to completely
separate the interface from the implementation. Would the header file
then look something like this?:

//compile with NDEBUG=1 to get rid of assertions


const int maxStack = 16;

class IStack
{
public:
IStack () :_top (0) {}
void Push (int i);
int Pop ();

void Push (int i)
{
assert (_top < maxStack);
_arr [_top] = i;
++_top;
}

int Pop ()
{
assert (_top > 0);
--_top;
return _arr [_top];
}


private:
int _arr [maxStack];
int _top;

};

In other words, everything that defines the class would go in the
class header, and the only code written in the implementation file
would be a call or calls to the constructor or member functions?

Cheers,

Deets
 
V

Victor Bazarov

Anon Email said:
Hi people,

I'm learning about header files in C++. The following is code from
Bartosz Milewski:

// Code

const int maxStack = 16;

class IStack
{
public:
IStack () :_top (0) {}
void Push (int i);
int Pop ();
private:
int _arr [maxStack];
int _top;
};

--------------
// Header file

#include "stack.h"
#include <cassert>
#include <iostream>
using std::cout;
using std::endl;

//compile with NDEBUG=1 to get rid of assertions

void IStack::push (int i)
{
assert (_top < maxStack);
_arr [_top] = i;
++_top;
}

int IStack::pop ()
{
assert (_top > 0);
--_top;
return _arr [_top];
}

--------------

I know this is very basic code. I also know that it's a non-standard
header filename/ file. I'm merely using this for demonstration
purposes. Let's pretend that in C++ it's possible to completely
^^^^^^^^^^^^^
I guess you mean "it's IMpossible", don't you?
separate the interface from the implementation. Would the header file
then look something like this?:

//compile with NDEBUG=1 to get rid of assertions


const int maxStack = 16;

class IStack
{
public:
IStack () :_top (0) {}
void Push (int i);
int Pop ();

void Push (int i)
{
assert (_top < maxStack);
_arr [_top] = i;
++_top;
}

int Pop ()
{
assert (_top > 0);
--_top;
return _arr [_top];
}


private:
int _arr [maxStack];
int _top;

};

In other words, everything that defines the class would go in the
class header, and the only code written in the implementation file
would be a call or calls to the constructor or member functions?

I am not sure what book you read on C++, but you don't need to
(actually you mustn't) declare your member functions before trying
to define them. Just throw away the declarations and keep the
definitions (which will also be declarations).

class has_definitions_inside
{
int foo()
{
return 42;
}
double bar()
{
return 3.14159;
}
}


Victor
 
J

John Carson

Anon Email said:
Hi people,

I'm learning about header files in C++. The following is code from
Bartosz Milewski:

// Code

const int maxStack = 16;

class IStack
{
public:
IStack () :_top (0) {}
void Push (int i);
int Pop ();
private:
int _arr [maxStack];
int _top;
};

--------------
// Header file

#include "stack.h"
#include <cassert>
#include <iostream>
using std::cout;
using std::endl;

//compile with NDEBUG=1 to get rid of assertions

void IStack::push (int i)
{
assert (_top < maxStack);
_arr [_top] = i;
++_top;
}

int IStack::pop ()
{
assert (_top > 0);
--_top;
return _arr [_top];
}

--------------

I know this is very basic code. I also know that it's a non-standard
header filename/ file. I'm merely using this for demonstration
purposes. Let's pretend that in C++ it's possible to completely
separate the interface from the implementation. Would the header file
then look something like this?:

//compile with NDEBUG=1 to get rid of assertions


const int maxStack = 16;

class IStack
{
public:
IStack () :_top (0) {}
void Push (int i);
int Pop ();

void Push (int i)
{
assert (_top < maxStack);
_arr [_top] = i;
++_top;
}

int Pop ()
{
assert (_top > 0);
--_top;
return _arr [_top];
}


private:
int _arr [maxStack];
int _top;

};

In other words, everything that defines the class would go in the
class header, and the only code written in the implementation file
would be a call or calls to the constructor or member functions?

Cheers,

Deets

You seem to be confusing implementation code and client code.

All declarations of the class object and all calls to the class member
functions are client code. Implementation code is basically code that
defines the member functions plus a class's data members. Your changes move
all the implementation code into the header file and, if anything, reduce
the separation between interface and implementation.

It should be pointed out that the most important aspect of
interface/implementation separation is not what file the code goes in. In
the most fundamental sense, a class's interface consists of its public
members. Accordingly, to maximise separation between interface and
implementation, you should minimise a class's public members. This usually
means making all data members private (or protected if absolutely necessary)
so that clients interact with class objects only through calling public
member functions. This allows you to change anything in the class except for
the signatures of the public member functions without necessitating any
change in client code.
 
J

John Carson

John Carson said:
All declarations of the class object and all calls to the class member
functions are client code.

I should have said "all calls to class member functions other than those
from other member functions are client code."
 
A

Anon Email

Thanks guys.
You seem to be confusing implementation code and client code.

Yes, you are right - I am confused. I'm confused by the terms
implementation code, client code and interface. And I'm unsure as to
why abstract data types are called "abstract".

1) Put simply, is client code non-class code?
2) Is the aim to make a class interface like a "skeleton" of the class
implementation?
3) Is the class interface typically found in your header file?
3) Is the class implementation typically found in your source file?
4) Are abstract data types "abstract" because they are specified
separate to implementation?
5) In Bjarne Stroustrup's "The C++ Programming Language" on p317, he
talks about the class "I_box," and seems to use the terms "interface"
and "implementation" interchangably. Is there such a thing as an
"implementation interface", as opposed to an interface?

The following is confusing for me:

" Our implementation choice is to use an array of integers. It would
be nice to be able to separate the interface from the implementation.
In some languages it is actually possible. Not so in C++ (or, at
least, not without some gymnastics). The reasons are mostly
technological. The compiler would have to have knowledge about all the
files involved in the project in order to allow for such separation.

In C++, the best we can do is to separate the details of the
implementation of some member functions into the implementation file.
The interface file, however, must contain the definition of the class,
and that involves specifying all the data members. Traditionally,
interfaces are defined in header files with the .h extension. Here is
the stack.h interface file."

This comes from the following page on abstract data types:

http://www.relisoft.com/book/lang/scopes/11abstr.html

I'm trying to envision his "ideal" situation, where the interface is
separated completely from the implementation. Any further insight
greatly appreciated.

Cheers,

Deets
 
J

Jeff Schwab

Anon said:
Thanks guys.




Yes, you are right - I am confused. I'm confused by the terms
implementation code, client code and interface. And I'm unsure as to
why abstract data types are called "abstract".

1) Put simply, is client code non-class code?

Those are unrelated issues. Here's how it usually works for me, when
I'm working on my own. In reality, there are often several people
involved in various steps of this process, e.g. step 1 might be done by
a manager or committee, steps 2 and 3 might be done by me, and step 4
might be done by someone assigned to help me.

1) I decide I need a program to do something, e.g. provide some
information or some service I can't easily get from my system already.

2) I write a basic, simplistic program to show the outline of what I
want to do. When the program needs to do something complicated, I
pretend I have a function or object that does the complicated bit. I
decide how I'd like to be able to call the function, what the inputs and
outputs should be. To make my skeletal program compile, I declare the
functions and classes; for example, if I need to send data over a
network, I might make up a function that looks like this:

void send_data_to_host( class Datum&, std::string const& host_name );

If I want to be able to do complicated things to the network connection,
I might define a class that looks like this:

class Packet;

class Network_Connecton
{
public:
enum Protocol { tcp, udp };

Network_Connection(
std::string const& host_name,
Protocol const& protocol =tcp );

~Network_Connection( );

void open(
std::string const& host_name,
Protocol const& protocol =tcp );

void close( ) throw( );

void send( Packet& );

void receive( Packet& );

// ... other operations ...
};

I don't define any of the functions yet, I just declare them and compile
my program to object code (with my compiler's -c flag). I keep doing
this and thinking about what sorts of functions and data structures I'd
like to have available. I work out the high-level issues, e.g. exactly
what outputs the program will provide, what inputs will be needed, how I
can break the program into discrete parts, etc.

3) I take all the made-up functions and classes I've declared and
separate them into categories, putting all the bits involving each
category into a separate ".hh" file. For example, I might find myself
with a "network.hh" file, a "user_interface.hh" file, and a "math.hh"
file. Each such file defines an *interface*. Whatever's left of the
original program (once I've moved my made-up declarations into separate
files) is called *client code*.

4) For each interface file, I write a corresponding ".cc" file that
defines all the functions I've declared. I write the definitions one at
a time. I don't worry too much about making the functions fast, I just
try to make sure that each one will provide exactly the output I wanted
when I was writing the client code. Most of the functions are
straight-forward, and I can write them pretty quickly. If a function is
taking an especially long time to write, or I think a function's
definition is getting too complicated, I do the same thing I did in step
1: I try to break the task into smaller bits, and declare new functions
to perform small parts of the function's task. The new, "helper"
functions don't need to be declared in the original interface files,
since the client code does not directly depend on them. The collection
of all these function definitions, helper functions, etc. is called the
*implementation code*. The combination of an interface file and its
corresponding implementation file is called a *module*. As I'm working
on a given module, I compile to object code now and then, so the
compiler has a chance to point out the mistakes I make as I'm working.

5) I take all the modules, and try to compile them together. At this
point, the compiler executes another program called a "linker." The
linker tries to make sure that each function and variable I used in the
client code has actually been defined in one of the modules.

6) I test the code to make sure it's right, and that I didn't make
mistakes like forgetting to release memory or file handles when they
were no longer needed. At this point, I usually wish I already had
written code to do the testing for me. (I'm trying now to get into the
habit of writing testing code before I even start writing the program.)

7) Once I'm pretty sure the program is working correctly, I start
*profiling* it to determine where it's spending its time. Usually, the
program spends most of its time in only a few of the functions. I pick
one of those functions, try to make it faster, and go back to step 5.
2) Is the aim to make a class interface like a "skeleton" of the class
implementation?

Yes, that's the basic idea.
3) Is the class interface typically found in your header file?
Yes.

3) Is the class implementation typically found in your source file?

Both headers and implementation files are "source files."
4) Are abstract data types "abstract" because they are specified
separate to implementation?

No. An abstract class is special, in that it does not have definitions
for all of its methods. Such an undefined method is called "pure
virtual." Since the class is not completely defined, it can never be
instantiated; that's what makes it "abstract." Such a class is useful
because each class "derived" from it can provide a different
implementation of each virtual function. This feature supports a design
style called "polymorphism." To understand polymorphism, you first need
to have a basic understanding of a technique called "inheritance." See
chapter 12 of TC++PL.
5) In Bjarne Stroustrup's "The C++ Programming Language" on p317, he
talks about the class "I_box," and seems to use the terms "interface"
and "implementation" interchangably. Is there such a thing as an
"implementation interface", as opposed to an interface?

No, although an interface file may actually contain part of the
implementation of a module. Bjarne is not using the terms
interchangeably; please feel free to post any quotes from the book that
you find confusing.
The following is confusing for me:

" Our implementation choice is to use an array of integers. It would
be nice to be able to separate the interface from the implementation.
In some languages it is actually possible. Not so in C++ (or, at
least, not without some gymnastics). The reasons are mostly
technological. The compiler would have to have knowledge about all the
files involved in the project in order to allow for such separation.

In C++, the best we can do is to separate the details of the
implementation of some member functions into the implementation file.
The interface file, however, must contain the definition of the class,
and that involves specifying all the data members. Traditionally,
interfaces are defined in header files with the .h extension. Here is
the stack.h interface file."

This comes from the following page on abstract data types:

http://www.relisoft.com/book/lang/scopes/11abstr.html

That's a load of garbage. C++ provides better support for safely
separating interface from implementation than any other language I know.
In fact, that single fact is probably the reason C++ is my favorite
language.

The first paragraph you listed does have a shred of truth: When a C++
module (or any client code) is compiled, the interfaces of all
supporting modules must be available. This differs somewhat from
interpreted languages like Java that support a feature called
"reflection." However, the compiler does *not* need to know about all
files in the project, thanks to "dynamic linking."

The second paragraph says that the data members of a class must be
included in the interface file. This is certainly possible, and is
often done for "concrete" data types, for which performance is critical.
For most classes, though, it is absolutely not necessary. Only the
methods of the interface must be specified in the interface file.
Classes implementing the interface are simply derived from the interface
class, and all the details are hidden in implementation files.
I'm trying to envision his "ideal" situation, where the interface is
separated completely from the implementation. Any further insight
greatly appreciated.

Cheers,

Deets

I hope I've managed to clear some of this up; I know it's confusing.
C++ supports a lot of different design styles, and I think Bjarne tries
to show in his book how these styles differ, and how they can be used
together. Really, there is no substitute for writing your own programs
to find out why all these different techniques are useful, and how an
interface differs from an implementation. If you really want to
understand how client code differs from library code, try writing your
own library of classes and functions to make some difficult task seem
easy. Then, try writing programs that use your library.

Good luck, and please feel free to criticize or question any part of the
above explanation.

-Jeff
 
J

John Carson

Anon Email said:
Thanks guys.


Yes, you are right - I am confused. I'm confused by the terms
implementation code, client code and interface. And I'm unsure as to
why abstract data types are called "abstract".

1) Put simply, is client code non-class code?

These definitions are not laid down as part of any standard. They are a
convenient shorthand with a somewhat flexible meaning depending on context.

Client code of class X might belong to some other class Y or might not
belong to any class. The important feature is that it doesn't belong to
class X.

Note that if you have a hierarchy of classes, then the calling of members of
one class by members of another class in the same hierarchy would not
normally be termed "client code" (particularly if such function calls are an
integrated part of the design of the hierarchy), but you might still
occasionally find it called "client code".
2) Is the aim to make a class interface like a "skeleton" of the class
implementation?

No. The aim is to expose as little of the class as is consistent with
allowing the clients of the class to make use of the functionality it
offers. Information about a class is supplied to clients on a "need to know"
basis. This is for three reasons:

a) It simplifies things for the client; there is less to understand,
b) It makes the implementation more robust because clients aren't free to
change variables and thereby cause problems elsewhere,
c) It makes for greater flexibility. If clients know how a class works, then
they will seek to make use of that in their code and the client code will
stop working if the way the class works changes. By minimising what clients
know about the way the class works, you minimise the risk that changing
something about the way a class works will break client code.
3) Is the class interface typically found in your header file?
Yes.

3) Is the class implementation typically found in your source file?

[you have two 3s] .h and .cpp files are both source files. The
implementation is typically found in the .cpp file.
4) Are abstract data types "abstract" because they are specified
separate to implementation?

Yes. The idea of "abstract data types" predates C++. Clients know what an
abstract data type can do for them, but don't know how it is accomplished.

Note that you will also find references to "abstract classes", which are
classes that contain at least one pure virtual function. This is a C++
language construct and is distinct from the more general concept of an
abstract data type.
5) In Bjarne Stroustrup's "The C++ Programming Language" on p317, he
talks about the class "I_box," and seems to use the terms "interface"
and "implementation" interchangably.
Is there such a thing as an
"implementation interface", as opposed to an interface?

If you start reading at p314, then it should be clear that Stroustrup
distinguishes interface and implementation quite sharply. Stroustrup is
discussing a complicated case in which the program code needs to be able to
work in multiple environments and where there is a complicated inheritance
hierarchy. He occasionally uses the word "implementation" somewhat flexibly,
e.g., by "implementation detail" he may mean "implementation detail in an
ideal design" as opposed to an implementation detail of the current design.
Like I said, words like "implementation" are not laid down in any standard
and may be used somewhat differently in different contexts.

The following is confusing for me:

" Our implementation choice is to use an array of integers. It would
be nice to be able to separate the interface from the implementation.
In some languages it is actually possible. Not so in C++ (or, at
least, not without some gymnastics). The reasons are mostly
technological. The compiler would have to have knowledge about all the
files involved in the project in order to allow for such separation.

In C++, the best we can do is to separate the details of the
implementation of some member functions into the implementation file.
The interface file, however, must contain the definition of the class,
and that involves specifying all the data members. Traditionally,
interfaces are defined in header files with the .h extension. Here is
the stack.h interface file."
This comes from the following page on abstract data types:

http://www.relisoft.com/book/lang/scopes/11abstr.html

I'm trying to envision his "ideal" situation, where the interface is
separated completely from the implementation. Any further insight
greatly appreciated.

His ideal situation is one where the private members of the class would not
need to be in the header file. If you really care about this, there is a
well known workaround whereby you can omit private members from the header
file by having the header file contain just a pointer to data members that
are stored in the .cpp file. This is know as the "pimpl idiom" (short for
"pointer to implementation"). See, e.g.,

http://c2.com/cgi/wiki?PimplIdiom

or do a Google search.
 
J

Jeffrey Schwab

Correction:

I see now that you were asking about abstract data types, not abstract
classes. Abstract, in the sense you used it, means only that the
implementation is hidden from the user. This usually means an extra
level of redirection is needed, and the redirection is usually through a
pointer. One popular approach is to have a *factory* or static method
return a pointer to a class implementing the interface, and another is
the "pimpl" method John Carson already mentioned.
 
A

Anon Email

Thanks Victor, John and Jeff!

For the most part, your explanations have clarified everything. Most
of the remaining confusion is related to areas that I've only touched
upon in C++, and I won't bother you with that right now. I do,
however, have a couple more niggly questions:

1) To Jeff:
Whatever's left of the
original program (once I've moved my made-up declarations into separate
files) is called *client code*.

This may be a dumb question, but I'll ask anyway. Your client code
ends up in a .cpp file, right? And it has no corresponding header
file, unlike all your implementation code files? I gather that the
client code is where your main function lies?

2) Is your use of ".hh" for header files your own convention?

3) To Victor:
I am not sure what book you read on C++, but you don't need to
(actually you mustn't) declare your member functions before trying
to define them. Just throw away the declarations and keep the
definitions (which will also be declarations).

Do you mean that you shouldn't declare member functions where no
member function definition exists? I gather that this is because the
declarations take up space? Jeff declares a number of functions before
defining them in his implementation code...hence the question.

Cheers, and thanks for such detailed and thorough answers,

Deets
 
J

Jeff Schwab

Anon said:
Thanks Victor, John and Jeff!

For the most part, your explanations have clarified everything. Most
of the remaining confusion is related to areas that I've only touched
upon in C++, and I won't bother you with that right now. I do,
however, have a couple more niggly questions:

1) To Jeff:




This may be a dumb question, but I'll ask anyway. Your client code
ends up in a .cpp file, right? And it has no corresponding header
file, unlike all your implementation code files? I gather that the
client code is where your main function lies?

That depends. :) In the example I listed, yes, you're correct that no
header is needed. However, sometimes your program has to fit into a
larger framework; e.g., when you are writing an OS kernel extension, or
a library for use by other people. In such cases, you have to provide a
header for those people (the "clients" of your code) to use.
2) Is your use of ".hh" for header files your own convention?

I "invented" it myself, but I'm sure I wasn't the first; I've since seen
it in other peoples' code. It makes a nice parallel to ".cc", which I
think was Bjarne's old extension when C++ was implemented mainly by the
preprocessor. It's supposed to stand for "C With Classes." Anyway, I
would have liked to use .h and .c, but they confuse certain compilers
and editors.
Cheers, and thanks for such detailed and thorough answers,

Deets

I'm very glad they were of use! :)

Thanks,
Jeff
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top