Inheritance question

V

vrishba

Hi,

Suppose we have

class CAbstractFile {

public:

virtual bool Open()=0;
virtual bool Read(long num_bytes,void *bufferp)=0;
virtual bool Write(long num_bytes,void *bufferp)=0;
virtual bool Close()=0;
};

class CDiskFile : public CAbstractFile {

private:

CString Path;
HANDLE Handle;

public:

// all implemented in CDiskFile.cpp
void SetPath(CString path);
virtual bool Open();
virtual bool Read(long num_bytes,void *bufferp);
virtual bool Write(long num_bytes,void *bufferp);
virtual bool Close();
};

class CRamFile : public CAbstractFile {

private:

void *BufferStart;
long BufferLength;
long Position;

public:

// all implemented in CRamFile.cpp
void SetRamBuffer(void *startp,long length);
virtual bool Open();
virtual bool Read(long num_bytes,void *bufferp);
virtual bool Write(long num_bytes,void *bufferp);
virtual bool Close();
};

Now i want to derive a new class CJpegFile that implements reading &
writing of Jpeg files.

I want that CJpegFile object can be a CDiskFile or a CRamFile,
so that we can read/write a jpeg file as well via a diskfile as well
via a ramfile.

How should this be done in good C++?

I can't find the answer, and i'm sorry if this is a stupid question.

Cheers,

Vrish
 
V

Victor Bazarov

Suppose we have

class CAbstractFile {

public:

virtual bool Open()=0;
virtual bool Read(long num_bytes,void *bufferp)=0;
virtual bool Write(long num_bytes,void *bufferp)=0;
virtual bool Close()=0;
};

class CDiskFile : public CAbstractFile {

private:

CString Path;
HANDLE Handle;

public:

// all implemented in CDiskFile.cpp
void SetPath(CString path);
virtual bool Open();
virtual bool Read(long num_bytes,void *bufferp);
virtual bool Write(long num_bytes,void *bufferp);
virtual bool Close();
};

class CRamFile : public CAbstractFile {

private:

void *BufferStart;
long BufferLength;
long Position;

public:

// all implemented in CRamFile.cpp
void SetRamBuffer(void *startp,long length);
virtual bool Open();
virtual bool Read(long num_bytes,void *bufferp);
virtual bool Write(long num_bytes,void *bufferp);
virtual bool Close();
};

Now i want to derive a new class CJpegFile that implements reading &
writing of Jpeg files.

I want that CJpegFile object can be a CDiskFile or a CRamFile,
so that we can read/write a jpeg file as well via a diskfile as well
via a ramfile.

How should this be done in good C++?

Something like

class CJpegFile : public CRamFile, public CDiskFile {
...
void SetIsDisk();
void SetIsRam(); // those two should probably throw if not closed
bool Open() {
if (isDisk)
CDiskFile::Open();
else
CRamFile::Open();
}
// others similarly
};

However, if you don't need the same CJpegFile to be able to write to
either disk or RAM at will, you'd be much better off with two classes
CJpegDisk and CJpegRam instead of one.

V
 
V

vrishba

Hi Victor,

Victor said:
Something like

class CJpegFile : public CRamFile, public CDiskFile {
...
void SetIsDisk();
void SetIsRam(); // those two should probably throw if not closed
bool Open() {
if (isDisk)
CDiskFile::Open();
else
CRamFile::Open();
}
// others similarly
};

What a pity that we can't use the C++ polymorphism here.

I thought that's what virtual functions are for, to automatically
switch between different implementations of a (abstract) base class.
However, if you don't need the same CJpegFile to be able to write to
either disk or RAM at will, you'd be much better off with two classes
CJpegDisk and CJpegRam instead of one.

Would that mean we have 2 times the same jpeg specific code, once using
the CDiskFile functions, and once using the CRamFile functions?

Cheers,

Vrish
 
V

Victor Bazarov

Hi Victor,




What a pity that we can't use the C++ polymorphism here.

I thought that's what virtual functions are for, to automatically
switch between different implementations of a (abstract) base class.




Would that mean we have 2 times the same jpeg specific code, once using
the CDiskFile functions, and once using the CRamFile functions?

Definitely not. What you need to do is abstract the jpeg specific code
and take it out of 'CJpegDisk' and 'CJpegRam' into 'CJpegGeneric'. Then
your 'CJpegDisk' would be something like

class CJpegDisk : public CDiskFile, public CJpegGeneric {

and all things from here.

Of course, you'd be much better off if you do all this with "policies",
see "Modern C++ Design" by A. Alexandrescu.

V
 
P

Phil Endecott

Suppose we have

class CAbstractFile { ...
class CDiskFile : public CAbstractFile { ...
class CRamFile : public CAbstractFile { ...

Now i want to derive a new class CJpegFile that implements reading &
writing of Jpeg files.

I want that CJpegFile object can be a CDiskFile or a CRamFile,
so that we can read/write a jpeg file as well via a diskfile as well
via a ramfile.

There are several ways of doing this. You need to think about how you
want to use the files.

I don't think that the methods of JpegFile include Read and Write.
Probably what you want to do with a JpegFile is things like Open,
Display, Print, ConvertToPng etc. So JpegFile is not a subclass of
AbstractFile. But it is *implemented* using an AbstractFile. So you
could have

class JpegFile {
private:
AbstractFile* file;

public:
JpegFile(char* fn): file(new DiskFile(fn) {...}
// Add a constructor to DiskFile that takes a filename

JpegFile(void* address): file(new RamFile(address) {...}
// Add a constructor to RamFile

~JpegFile() {delete file;}
// AbstractFile needs a virtual destructor

void print();
....
};


Does this help?

--Phil.
 
M

Mike Smith

Hi,

Suppose we have

class CAbstractFile {
};

class CDiskFile : public CAbstractFile {
};

class CRamFile : public CAbstractFile {
};

Now i want to derive a new class CJpegFile that implements reading &
writing of Jpeg files.

I want that CJpegFile object can be a CDiskFile or a CRamFile,
so that we can read/write a jpeg file as well via a diskfile as well
via a ramfile.

How should this be done in good C++?

Personally, I think this may be more of a design issue than a language
issue. It seems to me that the hierarchy you've built is a hierarchy of
file *systems*. JPEG is a file *format*; maybe it doesn't belong in
this hierarchy. How about something like:

class CJpegProcessor
{
return_type Read(CAbstractFile &, CImage &);
return_type Write(CAbstractFile &, CImage &);
};

where CImage is some image class that you've defined to store the image
data? CJpegProcessor "knows" what a JPEG file looks like and contains,
but it doesn't need to know anything about the vagaries of writing data
to disk vs. RAM vs. (say) flash, the way the classes in your hierarchy do.
 
V

vrishba

I think you and Phil are essentially saying the same thing.

And i agree with you that it's much better to do it this way, i.e. give
CJpegFile a pointer/reference to a CAbstractFile,
so it can use that to read/write a file, whatever type that is.

Thanks for your enlightening help guys!

Cheers,

Vrish
 
V

vrishba

Of course, you'd be much better off if you do all this with "policies",
see "Modern C++ Design" by A. Alexandrescu.

Interesting link, thanks Victor.

Cheers,

Vrish
 

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
474,206
Messages
2,571,069
Members
47,675
Latest member
KevinStepp

Latest Threads

Top