By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,334 Members | 1,861 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,334 IT Pros & Developers. It's quick & easy.

specifying interface without definition?

P: n/a
Hello!

Suppose I'm writing a library to write a binary representation
of some data to a stream. Let's say that to make it extensible
in the future I'm preceding the actual data with some info
like the number of fields, total length, etc. that make up
some kind of header, assuming the actual data may change
over time.

I was hoping to implement a 'class datafile' that would
represent the whole datafile, a 'class record' which would
consist of a header and the actual data. I want the 'record'
class to have a member to write it to a stream, like

record::write(ostream &out) {
// write record number
// write other stuff like sizeof(actual_data)
// write actual_data
}

I was aiming for a design that would allow the class
actual_data to vary, ie. NOT be defined in the library
I'm writing, but be defined in the program that uses
the library. Then I would write programs that would
define their own actual_data class and use the library
to store records into a datafile.

To make the library independent of actual_data I
have decided to only store a pointer to it, so the
record class would look like this
class record {
// some header data
actual_data *content;
}

Now, it turns out that if actual_data is non-POD then
I must provide some means to serialize it, like overloading
<< and >> or providing some save_to_bytes()/restore_from_bytes()
members. These would be used in record::write during
'write actual_data'. Of course these would have to be supplied
by the program using the library, as they depend on the precise
content of actual_data.

The problem is -- how do I convince the library that I can
call these functions using -> on the pointer to actual_data?
Obviously the library doesn't know what actual_data looks like...

So is there any way to tell the compiler "OK, I have a class
called actual_data that has some fields you don't know in
advance, so I can't give you a definition yet, but it definitely
has some get/put methods so you'll know how to store and restore
it?"

It would also be useful if actual_data could pass some info
to the library, like a 'my_size()' member function, but the
same problem occurs.

So how do I tell the compiler that I have a class that supports
some interface without revealing the whole class definition?

thanks in advance,
- J.
Dec 5 '05 #1
Share this Question
Share on Google+
3 Replies


P: n/a
Jacek Dziedzic wrote:
Hello!

Suppose I'm writing a library to write a binary representation
of some data to a stream. Let's say that to make it extensible
in the future I'm preceding the actual data with some info
like the number of fields, total length, etc. that make up
some kind of header, assuming the actual data may change
over time.

I was hoping to implement a 'class datafile' that would
represent the whole datafile, a 'class record' which would
consist of a header and the actual data. I want the 'record'
class to have a member to write it to a stream, like

record::write(ostream &out) {
// write record number
// write other stuff like sizeof(actual_data)
// write actual_data
}

I was aiming for a design that would allow the class
actual_data to vary, ie. NOT be defined in the library
I'm writing, but be defined in the program that uses
the library. Then I would write programs that would
define their own actual_data class and use the library
to store records into a datafile.

To make the library independent of actual_data I
have decided to only store a pointer to it, so the
record class would look like this
class record {
// some header data
actual_data *content;
}

Now, it turns out that if actual_data is non-POD then
I must provide some means to serialize it, like overloading
<< and >> or providing some save_to_bytes()/restore_from_bytes()
members. These would be used in record::write during
'write actual_data'. Of course these would have to be supplied
by the program using the library, as they depend on the precise
content of actual_data.

The problem is -- how do I convince the library that I can
call these functions using -> on the pointer to actual_data?
Obviously the library doesn't know what actual_data looks like...

So is there any way to tell the compiler "OK, I have a class
called actual_data that has some fields you don't know in
advance, so I can't give you a definition yet, but it definitely
has some get/put methods so you'll know how to store and restore
it?"

It would also be useful if actual_data could pass some info
to the library, like a 'my_size()' member function, but the
same problem occurs.

So how do I tell the compiler that I have a class that supports
some interface without revealing the whole class definition?

thanks in advance,
- J.


This is a classic case for templates. Your actual_data class can be a
template parameter to the datafile and/or record class.

#include <ostream>
#include <string>

template< class ActualData >
class DataFile
{
void SerializeTo( std::ostream& os )
{
os << actualData_;
}
// ...
private:
ActualData actualData_;
};

struct MyData
{
std::string name;
int id;
};

std::ostream operator<<( std::ostream& os, const MyData& data )
{
os << data.name << ' ' << data.id << std::endl;
return os;
};

void Foo()
{
DataFile<MyData> myDataFile;
// ...
myDataFile.SerializeTo( std::cout );
}

Cheers! --M

Dec 5 '05 #2

P: n/a
"Jacek Dziedzic" <jacek@no_spam.tygrys.no_spam.net> schrieb im Newsbeitrag
news:86**************************@news.chello.pl.. .
....
I was aiming for a design that would allow the class
actual_data to vary, ie. NOT be defined in the library
I'm writing, but be defined in the program that uses
the library. Then I would write programs that would
define their own actual_data class and use the library
to store records into a datafile.

To make the library independent of actual_data I
have decided to only store a pointer to it, so the
record class would look like this
class record {
// some header data
actual_data *content;
}

Now, it turns out that if actual_data is non-POD then
I must provide some means to serialize it, like overloading
<< and >> or providing some save_to_bytes()/restore_from_bytes()
members. These would be used in record::write during
'write actual_data'. Of course these would have to be supplied
by the program using the library, as they depend on the precise
content of actual_data.

The problem is -- how do I convince the library that I can
call these functions using -> on the pointer to actual_data?
Obviously the library doesn't know what actual_data looks like...


That's (also) what inheritance has been invented for. In your library you
can define some class, that defines all methods your library needs to call.
But you do not provide an implementation of those methods. Instead you
declare them as pure virtual functions. The only function, which you should
implement, is an empty, virtual destructor. You define this class in a
header file, which is used both in your library and the programs using the
library.

If your library only needs to read and write binary data from/to a stream,
such an interface yould look like

class AbstractData
{
public:
virtual ~AbstractData() {}
virtual int read(istream& stream, char* buffer, size_t bytesToRead)
= 0;
virtual int write(istream& stream, char* buffer, size_t
bytesWritten) = 0;
};

A program using your library can define its own class derived from
AbstractData. It must implement all pure virtual methods of its base class,
otherwise it would not be possible to create an instance of that class. Any
decent compiler will take care of that. Such an implementation could look
like this (I'll leave the actual implementation as an exercise :-)

class ConcretData: public AbstractData
{
int read(istream& stream, char* buffer, size_t bytesToRead);
int write(istream& stream, char* buffer, size_t bytesWritten);
// ...
// More stuff, that is not directly used by your library
};

If you like it, you can repeat "virtual" for all functions inherrited from
AbstractBase, but you don't have to. Once a function has been declared
virtual it will remaon so in all derived classes. That's also why there
should be an empty, virtual destructor in your base class. Even though there
is no data, that needs to be destructed, the virtual destructor allows you
to delete an instance of any derived class through a pointer to your
abstract base.

HTH
Heinz
Dec 5 '05 #3

P: n/a

Thanks a lot for the responses. I'd try the template way.

- J.
Dec 6 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.