 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Markus Svilans Guest
|
Posted: Fri Dec 29, 2006 10:10 am Post subject: Virtual function and inheritance question |
|
|
Hello,
My question involves virtual functions and inheritance.
Suppose we have a class structure, that consists of "data" classes, and
"processor" classes. The data classes are derived from BufferBase, and
customized in order to be able to a type of data (of any kind, such as
chunks of audio samples from a sound card). The processor classes are
derived from ProcessorBase, and are customized to handle
BufferBase-derived objects. Each BufferBase-derived class has a
corresponding ProcessorBase-derived class.
The following code summarizes this:
//=================
// Base classes
class BufferBase
{
public:
// Some arbitrary method for putting data into the buffer.
virtual void StoreData(void *data, int size);
};
class ProcessorBase
{
public:
// Virtual method, which derived classes implement to
// handle incoming data.
virtual void HandleBuffer(BufferBase &buffer) = 0;
};
//=================
// Derived classes
class BufferDerived : public BufferBase
{
// custom functions and data
};
// Class to handle BufferDerived objects
class ProcessorDerived : public ProcessorBase
{
public:
// Implement the pure virtual method in the base class
virtual void HandleBuffer(BufferBase &buffer)
{
// process data buffer
}
// Override the virtual method
virtual void HandleBuffer(BufferDerived &buffer)
{
// process data buffer
}
};
My question then is, if the following code is executed:
BufferBase buffer1;
BufferDerived buffer2;
// We will access the ProcessorDerived object through a
// base class pointer.
ProcessorBase *processor = new ProcessorDerived;
processor->HandleBuffer(buffer1); // Case #1
processor->HandleBuffer(buffer2); // Case #2
In each of the cases, #1 and #2, which version of the HandleBuffer()
method in the ProcessorDerived object gets called?
(My reasoning says that in both cases, HandleBuffer(BufferBase &buffer)
will be called, because the method is being invoked through a base
class pointer.)
Regards,
Markus. |
|
| Back to top |
|
 |
Markus Svilans Guest
|
Posted: Sun Dec 31, 2006 9:16 am Post subject: Re: Virtual function and inheritance question |
|
|
Salt_Peter wrote:
| Quote: | class ProcessorDerived : public ProcessorBase
{
// ...
public:
virtual void HandleBuffer(BufferBase &buffer)
{
std::cout << "ProcessorDerived::HandleBuffer(BufferBase
&buffer)\n";
std::cout << "buffer's type is " << typeid(buffer).name();
std::cout << std::endl;
}
};
I gather then that using RTTI is the only way to go here.
no, i just used typeid to show you that the reference is actually
pointing to a derived object with no need to cast anything. References,
not just pointers, work nicely with polymorphic objects.
In the event that you have some virtual member function in BufferBase
and its derivatives, these will get called polymorphicly and
transparently in void HandleBuffer(BufferBase &buffer).
|
I see that.
However, in my original question I was wondering what happens if you
call a virtual method in the base class, that has been overridden in a
derived class. In the example code I showed, ProcessorDerived had two
methods:
HandleBuffer(BufferBase &buffer) // inherited from ProcessorBase
HandleBuffer(BufferDerived &buffer) // a new, overridden version in
ProcessorDerived
After some experimenting, it became clear that the inherited version is
always the one that is invoked, when calling through a base class
pointer (in this case through a ProcessorBase pointer). The overridden
version is only called when calling from a derived class pointer.
| Quote: | Are there any good articles available online that outline the
performance penalties (if any) incurred when using RTTI?
There is no real need to use RTTI here. Polymorphism is what you need.
|
This is true.
However given the class hierarchy described in my original message,
what I'm looking for is some safe way of passing BufferBase-derived
objects to the correct ProcessorBase-derived objects.
Imagine we had the following additional classes:
// Imaginary class that stores a chunk of audio from an audio stream
class AudioBuffer : public BufferBase
{
private:
int timestamp;
// ... other data members and methods ...
public:
// ... public methods, constructors and destructors
};
// Imaginary class that stores a frame from a video data stream
class VideoFrameBuffer : public BufferBase
{
private:
// The video frame stores in some Bitmap object
Bitmap frame;
public:
// ... public methods, constructors and destructors
};
class AudioProcessor : public ProcessorBase
{
public:
// Inherited from ProcessorBase
virtual void HandleBuffer(BufferBase &buffer);
};
What I'm really after is a fast and safe way of automatically ensuring
that the AudioProcessor::HandleBuffer() method can only be passed
AudioBuffer objects, and not VideoFrameBuffer objects, or other objects
derived from BufferBase.
For example, if somehow an VideoFrameBuffer object gets passed to an
AudioProcessor, it would be nice if an exception were automatically
thrown.
Currently, the only method that comes to my mind is to use
dynamic_cast, or other form of RTTI, in AudioProcessor::HandleBuffer to
ensure that the passed buffer is an AudioBuffer.
Any ideas for how do to this?
(I thought of using a templated virtual method in the base class, but
apparently you can't create virtual methods that are also templates.)
| Quote: | The HandleBuffer() method may end up being called very frequently
(100's or 1000's of times per second) so I would like to make the
dispatching as fast as possible.
Contrary to popular opinion, in the situation you've described, there
is a cost in not using polymorphism. Specially when the cost includes
having to write the code. The cost of virtual calls themselves is
often, not always, a performance enhancement. You'ld have to compare.
|
I'm definitely a fan of polymorphism. I'm not trying to start any fires
when I say that in my opinion this is one of the great advantages of
C++ (and other OO languages) over C and other non-OO languages.
Regards,
Markus. |
|
| Back to top |
|
 |
Salt_Peter Guest
|
Posted: Sun Dec 31, 2006 10:10 am Post subject: Re: Virtual function and inheritance question |
|
|
Markus Svilans wrote:
| Quote: | Salt_Peter wrote:
class ProcessorDerived : public ProcessorBase
{
// ...
public:
virtual void HandleBuffer(BufferBase &buffer)
{
std::cout << "ProcessorDerived::HandleBuffer(BufferBase
&buffer)\n";
std::cout << "buffer's type is " << typeid(buffer).name();
std::cout << std::endl;
}
};
I gather then that using RTTI is the only way to go here.
no, i just used typeid to show you that the reference is actually
pointing to a derived object with no need to cast anything. References,
not just pointers, work nicely with polymorphic objects.
In the event that you have some virtual member function in BufferBase
and its derivatives, these will get called polymorphicly and
transparently in void HandleBuffer(BufferBase &buffer).
I see that.
However, in my original question I was wondering what happens if you
call a virtual method in the base class, that has been overridden in a
derived class. In the example code I showed, ProcessorDerived had two
methods:
HandleBuffer(BufferBase &buffer) // inherited from ProcessorBase
HandleBuffer(BufferDerived &buffer) // a new, overridden version in
ProcessorDerived
After some experimenting, it became clear that the inherited version is
always the one that is invoked, when calling through a base class
pointer (in this case through a ProcessorBase pointer). The overridden
version is only called when calling from a derived class pointer.
Are there any good articles available online that outline the
performance penalties (if any) incurred when using RTTI?
There is no real need to use RTTI here. Polymorphism is what you need.
This is true.
However given the class hierarchy described in my original message,
what I'm looking for is some safe way of passing BufferBase-derived
objects to the correct ProcessorBase-derived objects.
Imagine we had the following additional classes:
// Imaginary class that stores a chunk of audio from an audio stream
class AudioBuffer : public BufferBase
{
private:
int timestamp;
// ... other data members and methods ...
public:
// ... public methods, constructors and destructors
};
// Imaginary class that stores a frame from a video data stream
class VideoFrameBuffer : public BufferBase
{
private:
// The video frame stores in some Bitmap object
Bitmap frame;
public:
// ... public methods, constructors and destructors
};
class AudioProcessor : public ProcessorBase
{
public:
// Inherited from ProcessorBase
virtual void HandleBuffer(BufferBase &buffer);
};
What I'm really after is a fast and safe way of automatically ensuring
that the AudioProcessor::HandleBuffer() method can only be passed
AudioBuffer objects, and not VideoFrameBuffer objects, or other objects
derived from BufferBase.
|
No problem, use templates.
The compiler has no choice but to create those versions of the
templates you use. It can't call the wrong buffer with a processor
because no virtual member function would exist to match the call.
No RTTI needed unless you plan to make soup.
Of course, that means you'll need to store Audio things seperate from
Video things (ie: seperate containers). Note that default template
parameters below means that < > must still be used to declare the
derived processors in main().
#include <iostream>
#include <ostream>
#include <vector>
class BufferBase {
public:
BufferBase() { }
virtual ~BufferBase() { }
};
class AudioBuffer : public BufferBase { };
class VideoBuffer : public BufferBase { };
template< typename BufferType >
class ProcessorBase {
public:
virtual ~ProcessorBase() { }
virtual void HandleBuffer(BufferType &buffer) = 0;
};
template< typename BufferType = AudioBuffer >
class AudioProcessor : public ProcessorBase< BufferType > {
public:
virtual void HandleBuffer(BufferType &buffer) {
std::cout << "AudioProcessor::HandleBuffer(...)\n";
}
};
template< typename BufferType = VideoBuffer >
class VideoProcessor : public ProcessorBase< BufferType > {
public:
virtual void HandleBuffer(BufferType &buffer) {
std::cout << "VideoProcessor::HandleBuffer(...)\n";
}
};
int main() {
VideoBuffer vidbuf;
VideoProcessor< > vidproc;
vidproc.HandleBuffer( vidbuf );
AudioBuffer audiobuf;
AudioProcessor< > audioproc;
audioproc.HandleBuffer( audiobuf );
// test
// audioproc.HandleBuffer( vidbuf ); // error: no matching call
}
If you uncomment the error, the compiler doesn't even let you compile
the program. |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|